GNU/Linux >> Znalost Linux >  >> Linux

Naučte se zpracování chyb Bash na příkladu

V tomto článku uvádím několik triků, jak se vypořádat s chybovými stavy – některé striktně nespadají do kategorie zpracování chyb (reaktivní způsob, jak zvládnout neočekávané), ale také některé techniky, jak se chybám vyhnout dříve, než k nim dojde.

Případová studie:Jednoduchý skript, který stáhne zprávu o hardwaru z více hostitelů a vloží ji do databáze.

Řekněme, že máte cron na každém z vašich linuxových systémů a máte skript pro shromažďování informací o hardwaru z každého:

#!/bin/bash# Skript pro shromažďování stavu výstupu lshw z domácích serverů# Závislosti:# * LSHW:http://ezix.org/project/wiki/HardwareLiSter# * JQ:http://stedolan.github.io/jq/## Na každém počítači můžete něco takového spustit z cronu (CRON neznám, žádný strach:https://crontab-generator.org/)# 0 0 * * * /usr/sbin/lshw -json -quiet> /var/log/lshw-dump.json# Autor:Jose Vicente Nunez#declare -a servers=(dmaf5)DATADIR="$HOME/Documents/lshw-dump"/usr /bin/mkdir -p -v "$DATADIR"pro server v ${servers[*]}; do    echo "Navštěvování:$server"    /usr/bin/scp -o logLevel=Chyba ${server}:/var/log/lshw-dump.json ${DATADIR}/lshw-$server-dump.json &donewaitfor lshw in $(/usr/bin/find $DATADIR -type f -name 'lshw-*-dump.json'); do    /usr/bin/jq '.["product","vendor", "configuration"]' $lshwdone 

Pokud vše půjde dobře, shromažďujete soubory paralelně, protože nemáte více než deset systémů. Můžete si dovolit ssh pro všechny z nich najednou a poté zobrazit podrobnosti o hardwaru každého z nich.

Návštěva:DMAF5LSHW-DUMP.JSON 100% 54KB 136,9MB/S 00:00 "DMAF5 (výchozí řetězec)" "Besstar Tech Limited" {"Boot":"Normal", "Chassis":"Desktop" ",  "family":"Výchozí řetězec",  "sku":"Výchozí řetězec",  "uuid":"00020003-0004-0005-0006-000700080009"}

Zde je několik možností, proč se věci pokazily:

  • Váš přehled se nespustil, protože server nefungoval
  • Nemohli jste vytvořit adresář, do kterého je třeba uložit soubory
  • Chybí nástroje, které potřebujete ke spuštění skriptu
  • Nemůžete vyzvednout zprávu, protože váš vzdálený počítač selhal
  • Jeden nebo více přehledů je poškozených

Aktuální verze skriptu má problém – poběží od začátku do konce, chyby nebo ne:

./ collect_data_from_servers.sh Návštěva:MacMini2Visiting:Mac-Pro-1-1Visiting:dmaf5lshw-hump.json 100% 54KB 48.8mb/s 00:00 SCP:/var/Log/Log/LSHW.JSON :Žádný takový soubor nebo adresář scp:/var/log/lshw-dump.json:Chyba při analýze souboru nebo adresáře:Očekáván oddělovač mezi hodnotami na řádku 3, sloupci 9

Dále předvedu několik věcí, díky kterým bude váš skript robustnější a v některých případech se zotaví po selhání.

Nukleární možnost:Tvrdé selhání, rychlé selhání

Správný způsob, jak ošetřit chyby, je zkontrolovat, zda program skončil úspěšně nebo ne, pomocí návratových kódů. Zní to samozřejmě, ale návratové kódy, celé číslo uložené v bash $? nebo $! proměnná, mají někdy širší význam. Manuová stránka bash vám říká:

Pro účely shellu byl příkaz, který končí s nulovým exit
statem, úspěšný. Návratový stav nula znamená úspěch.
Nenulový výstupní stav znamená selhání. Když příkaz
skončí na fatálním signálu N, bash použije hodnotu 128+N jako
stav ukončení.

Jako obvykle byste si měli vždy přečíst manuálovou stránku skriptů, které voláte, abyste viděli, jaké jsou konvence pro každý z nich. Pokud jste programovali s jazykem, jako je Java nebo Python, pak jste pravděpodobně obeznámeni s jejich výjimkami, odlišným významem a tím, že ne se všemi se zachází stejně.

Pokud přidáte sadu -o errexit do vašeho skriptu, od tohoto okamžiku přeruší provádění, pokud existuje jakýkoli příkaz s kódem !=0 . Ale errexit se nepoužívá při provádění funkcí uvnitř if podmínku, takže místo abych si tuto výjimku pamatoval, raději dělám explicitní zpracování chyb.

Podívejte se na verzi dvě skriptu. Je to o něco lepší:

1 #!/bin/bash2 # Skript pro shromažďování stavu výstupu lshw z domácích serverů3 # Závislosti:4 # * LSHW:http://ezix.org/project/wiki/HardwareLiSter5 # * JQ:http://stedolan.github.io/jq/6 #7 # Na každém počítači můžete něco takového spustit z cronu (CRON neznám, žádný strach:https://crontab-generator.org/ ) 8 # 0 0 * * * /usr/sbin/lshw -json -quiet> /var/log/lshw-dump.json9 Autor:Jose Vicente Nunez10 #11 set -o errtrace # Povolí past chyb, kód bude volán, když dojde k chybě je detekován12 past "echo ERROR:Došlo k chybě v ${FUNCNAME-main context}, podrobnosti je třeba následovat" ERR13 deklarovat -a servers=(14 macmini215 mac-pro-1-116 dmaf517 )18 19 DATADIR="$HOME/ Documents/lshw-dump"20 pokud [ ! -d "$DATADIR" ]; potom 21   /usr/bin/mkdir -p -v "$DATADIR"|| "FATAL:Nepodařilo se vytvořit $DATADIR" &&exit 10022 fi 23 deklarovat -A server_pid24 pro server v ${servers[*]}; do25   echo "Navštěvování:$server"26   /usr/bin/scp -o logLevel=Chyba ${server}:/var/log/lshw-dump.json ${DATADIR}/lshw-$server-dump.json &27   server_pid [$server]=$! # Uložte PID scp daného serveru na později28 hotovo29 # Projděte všechny servery a:30 # Počkejte na návratový kód každého31 # Zkontrolujte výstupní kód z každého scp32 pro server v ${!server_pid[*]}; do33   počkat ${server_pid[$server]}34   otestovat $? -ne 0 &&echo "CHYBA:Kopírování z $serveru mělo problémy, nebude pokračovat" &&ukončí 10035 done36 pro lshw v $(/usr/bin/find $DATADIR -type f -name 'lshw-*-dump.json' ); do37   /usr/bin/jq '.["produkt","vendor", "configuration"]' $lshw38 hotovo 

Zde je to, co se změnilo:

  • Řádky 11 a 12, povoluji trasování chyb a přidal jsem „past“, která uživateli sděluje, že došlo k chybě a že jsou před ním turbulence. Možná budete chtít zabít svůj skript zde, ukážu vám, proč to nemusí být nejlepší.
  • Řádek 20, pokud adresář neexistuje, zkuste jej vytvořit na řádku 21. Pokud se vytvoření adresáře nezdaří, ukončete jej s chybou.
  • Na řádku 27, po spuštění každé úlohy na pozadí, zachytím PID a přiřadím ho ke stroji (vztah 1:1).
  • Na řádcích 33–35 čekám na scp úkol dokončit, získat návratový kód, a pokud se jedná o chybu, přerušit.
  • Na řádku 37 zkontroluji, zda lze soubor analyzovat, jinak skončím s chybou.

Jak tedy vypadá zpracování chyb nyní?

Návštěva:MacMini2Visiting:Mac-Pro-1-1Visiting:DMAF5LSHW-DUMP.JSON 100% 54KB 146.1MB/S 00:00 SCP:/VAR/LOG/LSHW-DUMP.JSON:Žádný takový soubor nebo directoryERROR:Došlo k chybě v hlavním kontextu, podrobnosti k následováníERROR:Kopírování z mac-pro-1-1 mělo problémy, nebude pokračovatcp:/var/log/lshw-dump.json:Žádný takový soubor nebo adresář

Jak můžete vidět, tato verze je lepší v odhalování chyb, ale je velmi nemilosrdná. Také nezjistí všechny chyby, že?

Když se zaseknete a přejete si mít budík

Kód vypadá lépe, až na to, že někdy je scp může uvíznout na serveru (při pokusu o kopírování souboru), protože server je příliš zaneprázdněn na to, aby odpověděl, nebo je ve špatném stavu.

Dalším příkladem je pokus o přístup k adresáři přes NFS, kde je $HOME je připojen ze serveru NFS:

/usr/bin/find $HOME -type f -name '*.csv' -print -fprint /tmp/report.txt 

A o hodiny později zjistíte, že bod připojení NFS je zastaralý a váš skript se zasekl.

Řešením je časový limit. A na záchranu přichází časový limit GNU:

/usr/bin/timeout --kill-after 20.0s 10.0s /usr/bin/find $HOME -type f -name '*.csv' -print -fprint /tmp/report.txt 

Zde se snažíte pravidelně zabít (signál TERM) proces pěkně po 10,0 sekundách po jeho spuštění. Pokud po 20,0 sekundách stále běží, odešlete signál KILL (kill -9 ). Máte-li pochybnosti, zkontrolujte, které signály váš systém podporuje (kill -l , například).

Pokud to z mého dialogu není jasné, podívejte se na skript, aby byl jasnější.

/usr/bin/time /usr/bin/timeout --kill-after=10.0s 20.0s /usr/bin/sleep 60sreal    0m20.003suser    0m0.000ssys    0m0.003s 

Vraťte se k původnímu skriptu a přidejte několik dalších možností a máte verzi tři:

 1 #!/bin/bash 2 # Skript pro shromažďování stavu výstupu lshw z domácích serverů 3 # Závislosti:4 # * Otevřete SSH:http://www.openssh.com/portable.html 5 # * LSHW:http://ezix.org/project/wiki/HardwareLiSter 6 # * JQ:http://stedolan.github.io/jq/ 7 # * časový limit:https://www.gnu.org/software /coreutils/ 8 # 9 # Na každém počítači můžete něco takového spustit z cronu (CRON neznám, žádný strach:https://crontab-generator.org/) 10 # 0 0 * * * /usr/sbin /lshw -json -quiet> /var/log/lshw-dump.json 11 # Autor:Jose Vicente Nunez 12 # 13 set -o errtrace # Povolte err trap, kód bude volán, když je zjištěna chyba 14 trap "echo CHYBA:V ${FUNCNAME-main context} došlo k chybě, podrobnosti je třeba následovat" ERR 15 16 deklarovat -a dependencies=(/usr/bin/timeout /usr/bin/ssh /usr/bin/jq) 17 pro závislost v ${dependencies[@]}; do 18     pokud [ ! -x $závislost ]; potom 19         echo "ERROR:Missing $dependency" 20         exit 100 21     fi 22 hotovo 23 24 deklarovat -a servers=( 25 macmini2 26 mac-pro-1-1 27 dmaf3 1 $ 1 function echo "Visiting:$server" 33     /usr/bin/timeout --kill-after 25.0s 20.0s \ 34         /usr/bin/scp \ 35             -o BatchMode=yes  vel 3    7 –  7 – odhlásit se   36 =5 \ 38             -o ConnectionAttempts=3 \ 39             ${server}:/var/log/lshw-dump.json ${DATADIR}/lshw-$server-dump.json 40     vrátit $? 41 } 42 43 DATADIR="$HOME/Documents/lshw-dump" 44 pokud [ ! -d "$DATADIR" ]; potom 45     /usr/bin/mkdir -p -v "$DATADIR"|| "FATAL:Nepodařilo se vytvořit $DATADIR" &&exit 100 46 fi 47 deklarovat -A server_pid 48 pro server v ${servers[*]}; do 49     remote_copy $server &50     server_pid[$server]=$! # Uložte PID scp daného serveru na později 51 hotovo 52 # Projděte všechny servery a:53 # Počkejte na návratový kód každého 54 # Zkontrolujte výstupní kód z každého scp 55 pro server v ${!server_pid [*]}; udělat 56     počkat ${server_pid[$server]} 57     otestovat $? -ne 0 &&echo "CHYBA:Kopírování z $serveru mělo problémy, nebude pokračovat" &&exit 100 58 hotovo 59 pro lshw v $(/usr/bin/find $DATADIR -type f -name 'lshw-*-dump. json'); do 60     /usr/bin/jq '.["product","vendor", "configuration"]' $lshw 61 hotovo 

Jaké jsou změny?:

  • Mezi řádky 16–22 zkontrolujte, zda jsou k dispozici všechny požadované nástroje závislostí. Pokud se nemůže spustit, pak ‚Houstone máme problém.‘
  • Vytvořili remote_copy funkce, která používá časový limit k zajištění scp skončí nejpozději za 45,0 s – řádek 33.
  • Přidán časový limit připojení 5 sekund namísto výchozího nastavení TCP – řádek 37.
  • Přidán nový pokus do scp na řádku 38 – 3 pokusy, které mezi každým čekají 1 sekundu.

Existují další způsoby, jak to zkusit znovu, když dojde k chybě.

Čekání na konec světa – jak a kdy to zkusit znovu

Všimli jste si, že do scp byl přidán nový pokus příkaz. Ale to se opakuje pouze u neúspěšných připojení, co když příkaz selže během kopírování?

Někdy chcete prostě selhat, protože je velmi malá šance na zotavení z problému. Systém, který například vyžaduje opravy hardwaru, nebo se můžete vrátit zpět do sníženého režimu – což znamená, že můžete pokračovat v práci systému bez aktualizovaných dat. V těchto případech nemá smysl čekat věčně, ale pouze po určitou dobu.

Zde jsou změny v remote_copy , aby to bylo stručné (verze čtyři):

#!/bin/bash# Vynechaný kód kvůli přehlednosti...declare REMOTE_FILE="/var/log/lshw-dump.json"declare MAX_RETRIES=3# Bla bla bla...funkce remote_copy {    local server=$1    local retries=$2    local now=1    status=0    while [ $now -le $retries ]; do        echo "INFO:Pokus o kopírování souboru z:$server, pokus=$now"        /usr/bin/timeout --kill-after 25.0s 20.0s \            /usr/bin/scp \  de -                          logLevel=Error \                -o ConnectTimeout=5 \                -o ConnectionAttempts=3 \                ${server}:$REMOTE_FILE ${DATADIR}/lshwson lshw-$ stav ? if [ $stav -ne 0 ]; then            sleep_time=$(((NÁHODNĚ % 60)+ 1))            echo „UPOZORNĚNÍ:Kopírování se nezdařilo pro $server:$REMOTE_FILE. Čekání '${sleep_time} sekund', než to zkusíte znovu...“      /uspání  ${sleep_time}s        else            přestávka # Vše v pořádku, nemá smysl čekat...        fi        ((nyní=nyní+1))    hotovo    return $status}DATADIR="$HOME/Documents/lshw-dump"if [ ! -d "$DATADIR" ]; potom    /usr/bin/mkdir -p -v "$DATADIR"|| "FATAL:Nepodařilo se vytvořit $DATADIR" &&ukončete 100fideclare -A server_pidfor server v ${servers[*]}; do    remote_copy $server $MAX_RETRIES &    server_pid[$server]=$! # Uložte PID scp daného serveru pro pozdější provedení# Projděte všechny servery a:# Počkejte na návratový kód každého z nich# Zkontrolujte výstupní kód z každého serveru scpfor v ${!server_pid[*]}; udělat    počkat ${server_pid[$server]}    otestovat $? -ne 0 &&echo "CHYBA:Kopírování z $serveru mělo problémy, nebude pokračovat" &&exit 100done# Bla bla bla, zpracujte soubory, které jste právě zkopírovali... 

Jak to teď vypadá? V tomto běhu mám jeden systém mimo (mac-pro-1-1) a jeden systém bez souboru (macmini2). Můžete vidět, že kopie ze serveru dmaf5 funguje okamžitě, ale u ostatních dvou je před ukončením opakování náhodného času mezi 1 a 60 sekundami:

INFO:Pokus o kopírování souboru z:macmini2, pokus=1INFO:Pokus o kopírování souboru z:mac-pro-1-1, pokus=1INFO:Pokus o kopírování souboru z:dmaf5, pokus=1scp:/var/log/lshw-dump.json:Žádný takový soubor nebo adresář CHYBA:Došlo k chybě v hlavním kontextu, podrobnosti je třeba sledovat UPOZORNĚNÍ:Kopírování se nezdařilo pro macmini2:/var/log/lshw-dump.json. Čekání '60 sekund' před dalším pokusem...ssh:připojte se k hostiteli mac-pro-1-1 port 22:Žádná cesta k hostiteliERROR:Došlo k chybě v hlavním kontextu, podrobnosti je třeba sledovat VAROVÁNÍ:Kopírování selhalo pro mac-pro -1-1:/var/log/lshw-dump.json. Čekání '32 sekund' před dalším pokusem...INFO:Pokus o kopírování souboru z:mac-pro-1-1, pokus=2ssh:připojení k hostiteli mac-pro-1-1 port 22:Žádná cesta k hostiteliERROR:Došlo k chybě v hlavním kontextu, podrobnosti, které je třeba sledovat VAROVÁNÍ:Kopírování se nezdařilo pro mac-pro-1-1:/var/log/lshw-dump.json. Čekání '18 sekund' před dalším pokusem...INFO:Pokus o kopírování souboru z:macmini2, pokus=2scp:/var/log/lshw-dump.json:Žádný takový soubor nebo adresář ERROR:Došlo k chybě v hlavním kontextu , podrobnosti k dodržení UPOZORNĚNÍ:Kopírování se nezdařilo pro macmini2:/var/log/lshw-dump.json. Čekání '3 sekundy' před dalším pokusem...INFO:Pokus o kopírování souboru z:macmini2, pokus=3scp:/var/log/lshw-dump.json:Žádný takový soubor nebo adresář CHYBA:V hlavním kontextu došlo k chybě , podrobnosti k dodržení UPOZORNĚNÍ:Kopírování se nezdařilo pro macmini2:/var/log/lshw-dump.json. Čekání '6 sekund' před dalším pokusem...INFO:Pokus o kopírování souboru z:mac-pro-1-1, pokus=3ssh:připojení k hostiteli mac-pro-1-1 port 22:Žádná cesta k hostiteliERROR:Došlo k chybě v hlavním kontextu, podrobnosti, které je třeba sledovat VAROVÁNÍ:Kopírování se nezdařilo pro mac-pro-1-1:/var/log/lshw-dump.json. Čekání '47 sekund' před dalším pokusem...CHYBA:Došlo k chybě v hlavním kontextu, podrobnosti k následováníERROR:Kopírování z mac-pro-1-1 mělo problémy, nebude pokračovat 

Pokud selžu, musím to celé opakovat? Pomocí kontrolního bodu

Předpokládejme, že vzdálená kopie je nejdražší operací celého tohoto skriptu a že jste ochotni nebo schopni tento skript spustit znovu, třeba pomocí cron nebo to udělejte ručně dvakrát během dne, abyste zajistili, že si soubory vyzvednete, pokud je jeden nebo více systémů mimo provoz.

Pro ten den byste mohli vytvořit malou „mezipaměť stavu“, kam zaznamenáte pouze úspěšné operace zpracování na stroji. Pokud je tam nějaký systém, pak se neobtěžujte znovu zkontrolovat tento den.

Některé programy, jako Ansible, dělají něco podobného a umožňují vám po selhání znovu vyzkoušet hru na omezeném počtu počítačů (--limit @/home/user/site.retry ).

Nová verze (verze pět) skriptu má kód pro zaznamenání stavu kopie (řádky 15-33):

15 deklarovat SCRIPT_NAME=$(/usr/bin/basename $BASH_SOURCE)|| exit 10016 deklarovat YYYYMMDD=$(/usr/bin/date +%Y%m%d)|| exit 10017 deklarovat CACHE_DIR="/tmp/$SCRIPT_NAME/$YYYYMMDD"18 # Logika pro každodenní čištění adresáře mezipaměti zde není zobrazena19, pokud [ ! -d "$CACHE_DIR" ]; then20  /usr/bin/mkdir -p -v "$CACHE_DIR"|| exit 10021 fi22 trap "/bin/rm -rf $CACHE_DIR" INT KILL2324 funkce check_previous_run {25  local machine=$126  test -f $CACHE_DIR/$machine &&return 0|| return 127 }2829 function mark_previous_run {30    machine=$131    /usr/bin/touch $CACHE_DIR/$machine32    return $?33 } 

Všimli jste si pasti na lince 22? Pokud je skript přerušen (zabit), chci se ujistit, že je zneplatněna celá mezipaměť.

A pak přidejte tuto novou pomocnou logiku do remote_copy funkce (řádky 52-81):

52 function remote_copy {53    local server=$154    check_previous_run $server55    test $? -eq 0 &&echo "INFO:$1 proběhl úspěšně předtím. Neprovádí se znovu" &&return 056    local retries=$257    local now=158    status=059    while [ $now -le $retries ]; do60        echo "INFO:Pokus o zkopírování souboru z:$server, pokus=$now"61        /usr/bin/timeout --kill-after 25.0s 20.0s \62            /usr/bin/scp   /usr/bin/scp   /usr/bin/scp  \63  ch  de   es  \63  ch  =  \ 64 -o loglevel =error \ 65 -o connectTimeout =5 \ 66 -o connecTampts =3 \ 67 $ {Server}:$ remote_file $ {Datadir} /lshw-$Server -dump.json68 Stav =$ 69, pokud [ $stav -ne 0 ]; then70            sleep_time=$(((NÁHODNĚ % 60)+ 1))71            echo „UPOZORNĚNÍ:Kopírování se nezdařilo pro $server:$REMOTE_FILE. Čekání '${sleep_time} sekund', než to zkusíte znovu... 72   bin   /us   bin /sleep ${sleep_time}s73        else74            přestávka # Vše v pořádku, nemá smysl čekat...75        fi76        ((nyní=nyní+1))77    hotovo78    test $status -eq 7 $ spustit před 7 $?9 mark_serv -ne 0 &&status=180    return $status81 } 

Při prvním spuštění se vytiskne nová zpráva pro adresář mezipaměti:

./collect_data_from_servers.v5.sh/usr/bin/mkdir:vytvořený adresář '/tmp/collect_data_from_servers.v5.sh'/usr/bin/mkdir:vytvořený adresář '/tmp/collect_data_from_servers.v5.sh /20210612'CHYBA:V hlavním kontextu došlo k chybě, podrobnosti je třeba sledovatINFO:Pokus o kopírování souboru z:macmini2, pokus=1ERROR:V hlavním kontextu došlo k chybě, podrobnosti je třeba sledovat 

Pokud jej spustíte znovu, skript ví, že dma5f je připraveno, není třeba opakovat kopii:

./collect_data_from_servers.v5.shINFO:dmaf5 dříve úspěšně běžel. Nedělá se znovu CHYBA:Došlo k chybě v hlavním kontextu, podrobnosti ke sledováníINFO:Pokus o kopírování souboru z:macmini2, pokus=1CHYBA:Došlo k chybě v hlavním kontextu, podrobnosti ke sledováníINFO:Pokus o kopírování souboru z:mac-pro- 1-1, pokus=1 

Představte si, jak se to zrychlí, když máte více strojů, které by neměly být znovu navštěvovány.

Zanechání drobků:Co protokolovat, jak protokolovat a podrobný výstup

Pokud jste jako já, mám rád trochu kontextu, s nímž se dá korelovat, když se něco pokazí. echo příkazy ve skriptu jsou hezké, ale co kdybyste k nim mohli přidat časové razítko.

Pokud používáte logger , můžete výstup uložit na journalctl pro pozdější kontrolu (i agregaci s jinými nástroji). Nejlepší na tom je, že ukážete sílu journalctl hned.

Takže místo pouhého provádění echo , můžete také přidat volání logger takto pomocí nové funkce bash nazvané ‚zpráva “:

SCRIPT_NAME=$(/usr/bin/basename $BASH_SOURCE)|| exit 100FULL_PATH=$(/usr/bin/realpath ${BASH_SOURCE[0]})|| exit 100set -o errtrace # Povolte err trap, kód bude volán, když je zjištěna chybatrap "echo ERROR:Došlo k chybě v ${FUNCNAME[0]-main context}, podrobnosti je třeba následovat" ERRdeclare CACHE_DIR="/tmp /$SCRIPT_NAME/$YYYYMMDD"function message {    message="$1"    func_name="${2-unknown}"    priorita=6    if [ -z "$2" ]; potom        echo "INFO:" $message    else        echo "ERROR:" $message        priorita=0    fi    /usr/bin/logger --journald< 

Vidíte, že jako součást zprávy můžete uložit samostatná pole, jako je priorita, skript, který zprávu vytvořil atd.

Jak je to tedy užitečné? No, můžete získat zprávy mezi 13:26 a 13:27, pouze chyby (priorita=0 ) a pouze pro náš skript (collect_data_from_servers.v6.sh ) takto, výstup ve formátu JSON:

journalctl --od 13:26 --do 13:27 --output json-pretty PRIORITY=0 MESSAGE_ID=collect_data_from_servers.v6.sh 
{"_boot_id":"DFCDA9A1A1CD406EBD88A339BEC96FB6", "_AUDIT_LOGINUID":"1000", "Syslog_Identifier":"Logger", "Priorit" "_transport" "_transport" "_transport", "_transport", "_transport", "_transport", ". :"Unconfined_u:nekonfined_r:nekonfinováno_t:s0-s0:c0.c1023", "__realtime_timestamp":"1623518797641880", "_audit_session":"3", "_gid" _gid ":" 1000 ",". sh",        "MESSAGE" :"Kopírování se nezdařilo pro macmini2:/var/log/lshw-dump.json. Čekání '45 sekund', než to zkusíte znovu...",        "_CAP_EFFECTIVE" :"0",        "CODE_FUNC" :"remote_copy", "_MACHINE_ID":"60d7a3f69b674aaebb600c0e82e01d05", "_COMM":"logger", "CODE_FILE":"/home/josevnz/BashError/collect_data_from_servers.v6.sh", "_PID" "41832", "__MONOTONIC_TIMESTAMP" :"25928272252",        "_HOSTNAME" :"dmaf5",        "_SOURCE_REALTIME_TIMESTAMP" :"1623518797641843",        "__CURSOR" :"sf6a=4567" dedd8143df97;i=1f826;b=dfcda9a1a1cd406ebd88a339bec96fb6;m=60972097c;t=5c494ed383898;x=921c71966b8943e3" } 0 0" " > 00"

Protože se jedná o strukturovaná data, ostatní sběrači protokolů mohou procházet všechny vaše počítače, agregovat protokoly vašich skriptů a vy pak máte nejen data, ale také informace.

Můžete se podívat na celou verzi šest skriptu.

Nebuďte tak horliví po výměně dat, dokud je nezkontrolujete.


Pokud jste si všimli od samého začátku, kopíroval jsem poškozený soubor JSON znovu a znovu:

Chyba analýzy:Očekávaný oddělovač mezi hodnotami na řádku 4, sloupci 11ERROR při analýze '/home/josevnz/Documents/lshw-dump/lshw-dmaf5-dump.json' 

Tomu lze snadno zabránit. Zkopírujte soubor do dočasného umístění a pokud je soubor poškozen, nepokoušejte se nahradit předchozí verzi (a ponechte špatnou ke kontrole. řádky 99–107 verze sedm skriptu):

function remote_copy {    local server=$1    check_previous_run $server    test $? -eq 0 &&zpráva "$1 proběhl úspěšně předtím. Nedělá se znovu" &&return 0    local retries=$2    local now=1    status=0    while [ $now -le $retries ]; do        message "Pokouším se zkopírovat soubor z:$server, pokus=$now"        /usr/bin/timeout --kill-after 25.0s 20.0s \            /usr/bin/scp \                              Bat           Bat          Chyba \                -o ConnectTimeout=5 \                -o ConnectionAttempts=3 \                ${server}:$REMOTE_FILE ${DATADIR}/lshump . $ stav $ server. if [ $stav -ne 0 ]; potom            sleep_time=$(((NÁHODNĚ % 60)+ 1))            zpráva „Kopírování se nezdařilo pro $server:$REMOTE_FILE. Čeká se '${sleep_time} sekund', než to zkusíte znovu...“ ${FUNCNAME[0]     /   usr/bin/sleep ${sleep_time}s        else            přestávka # Vše v pořádku, nemá smysl čekat...        fi        ((nyní=nyní+1))    hotovo    if [ $status -eq 0 ]; potom        /usr/bin/jq '.' ${DATADIR}/lshw-$server-dump.json.$$> /dev/null 2>&1        status=$? if [ $stav -eq 0 ]; potom            /usr/bin/mv -v -f ${DATADIR}/lshw-$server-dump.json.$$ ${DATADIR}/lshw-$server-dump.json &&mark_previous_run $server            test $? -ne 0 &&status=1        else            zpráva "${DATADIR}/lshw-$server-dump.json.$$ Je poškozen. Odcházím ke kontrole..." ${FUNCNAME[0]}        fi    fi    vrátit $status} 

Vyberte si správné nástroje pro daný úkol a připravte si kód z prvního řádku

Jedním z velmi důležitých aspektů zpracování chyb je správné kódování. Pokud máte ve svém kódu špatnou logiku, žádné množství zpracování chyb jej nezlepší. Aby to bylo krátké a související s bash, poskytnu vám níže několik tipů.

Před spuštěním skriptu byste VŽDY měli zkontrolovat chybnou syntaxi:

bash -n $my_bash_script.sh 

Vážně. Mělo by to být stejně automatické jako provádění jakéhokoli jiného testu.

Přečtěte si manuálovou stránku bash a seznamte se s nezbytnými možnostmi, jako jsou:

set -xvmy_complicated_instruction1my_complicated_instruction2my_complicated_instruction3set +xv 

Pomocí ShellCheck zkontrolujte své bash skripty

Když se vaše skripty začnou zvětšovat, je velmi snadné přehlédnout jednoduché problémy. ShellCheck je jedním z těch nástrojů, které vás ochrání před chybami.

shellcheck collect_data_from_servers.v7.shIn collect_data_from_servers.v7.sh řádek 15:pro závislost v ${dependencies[@]}; do                  ^----------------^ SC2068:Rozšíření pole s dvojitými uvozovkami, aby se zabránilo opětovnému rozdělení prvků. V collect_data_from_servers.v7.sh řádek 16:    pokud [ ! -x $závislost ]; potom              ^---------^ SC2086:Dvojité uvozovky, aby se zabránilo globování a dělení slov. Měli jste na mysli:     pokud [ ! -x "$závislost" ]; pak... 

Pokud vás zajímá, finální verze skriptu po absolvování ShellCheck je zde. Čisté.

Všimli jste si něčeho s procesy scp na pozadí

Pravděpodobně jste si všimli, že pokud skript zabijete, zanechá za sebou některé rozvětvené procesy. To není dobré, a to je jeden z důvodů, proč raději používám nástroje jako Ansible nebo Parallel ke zpracování tohoto typu úloh na více hostitelích a nechám frameworky, aby provedly správné vyčištění za mě. Pro řešení této situace můžete samozřejmě přidat další kód.

Tento bash skript by mohl potenciálně vytvořit vidlicovou bombu. Nemá žádnou kontrolu nad tím, kolik procesů se má spustit současně, což je ve skutečném produkčním prostředí velký problém. Existuje také omezení počtu souběžných relací ssh, které můžete mít (natož spotřebovávat šířku pásma). Opět jsem napsal tento fiktivní příklad v bash, abych vám ukázal, jak můžete vždy vylepšit program, aby lépe zvládal chyby.

Pojďme si to zrekapitulovat

[ Stáhnout nyní:Průvodce systémového administrátora skriptováním v Bash. ]

1.  Musíte zkontrolovat návratový kód svých příkazů. To by mohlo znamenat rozhodnutí opakovat, dokud se přechodný stav nezlepší, nebo zkratovat celý skript.
2. Když už mluvíme o přechodných podmínkách, nemusíte začínat od nuly. Můžete uložit stav úspěšných úloh a pak to zopakovat od tohoto okamžiku.
3. Bash 'past' je tvůj přítel. Použijte jej pro čištění a zpracování chyb.
4. Při stahování dat z jakéhokoli zdroje předpokládejte, že jsou poškozená. Nikdy nepřepisujte svou dobrou datovou sadu čerstvými daty, dokud neprovedete nějaké kontroly integrity.
5. Využijte journalctl a vlastní pole. Můžete provádět sofistikované vyhledávání problémů a dokonce tato data odesílat do agregátorů protokolů.
6. Můžete zkontrolovat stav úloh na pozadí (včetně dílčích shellů). Nezapomeňte uložit PID a počkat na něj.
7. A nakonec:Použijte pomocníka Bash, jako je ShellCheck. Můžete si jej nainstalovat do svého oblíbeného editoru (jako je VIM nebo PyCharm). Budete překvapeni, kolik chyb zůstane ve skriptech Bash neodhaleno...

Pokud se vám tento obsah líbil nebo byste jej chtěli rozšířit, kontaktujte tým na adrese [email protected].


Linux
  1. Zpracování chyb ve skriptech Bash

  2. Sazba -a Je zadávání chyby ve skriptu?

  3. Proměnná Curl Outfile nefunguje ve skriptu Bash?

  1. Chyba skriptu Bash:Očekává se celočíselný výraz?

  2. Chyba Odstraňování problémů s neplatným názvem hostitele

  3. Bash Script - příklad Hello World

  1. Speciální parametry Bash vysvětlené pomocí 4 příkladů shellových skriptů

  2. Bash ignoruje chybu pro konkrétní příkaz

  3. Jak deklarovat 2D pole v bash