Ako debugovať bug, ktorý sa nedá vyvolať na povel: nástroj na čakanie na dôkaz
Nie príbeh o vyriešenom bugu — príbeh o tom, čo urobiť skôr, než sa dá bug vôbec vyriešiť: postaviť nástroj, ktorý zachytí dôkaz v momente, keď sa problém náhodou stane.
Dva problémy, ktoré sa nedajú vyvolať na povel
Pri používaní USB-C dock-u na pracovnom laptope sa občas dejú dve veci: pri zapojení sa niekedy nenačítajú všetky monitory, a laptop sa niekedy nevie vypnúť alebo uspať, keď je dock pripojený. Oba problémy majú spoločnú vlastnosť, ktorá z nich robí niečo iné než bežný bug — sú intermitentné. Zapoj dock desaťkrát, deväťkrát to funguje bez problému, raz nie. Skús to zámerne zopakovať, aby si to videl ešte raz, a väčšinou sa to práve teraz nestane.
Bežný spôsob debugovania — spusti príkaz, pozri si výstup, over hypotézu — tu jednoducho nefunguje. Nemáš čo spustiť v momente, keď sa problém deje, lebo nevieš, kedy nastane. Riešenie preto nebolo "poď to hneď opraviť" — bolo to "postav niečo, čo beží ticho na pozadí a zachytí dôkaz, presne keď sa to náhodou stane".
Ako dock vôbec pripája monitory
Prvý krok bol overiť, cez aký mechanizmus dock vlastne monitory pripája — dôležité pre to, kde vôbec hľadať. Kontrola potvrdila natívny USB-C/Thunderbolt DisplayPort alt-mode passthrough (kernel moduly pre typec a thunderbolt), nie extra userspace driver typu DisplayLink. To zúžilo podozrenie smerom k časovaniu hardvérového hotplug procesu na úrovni jadra, nie k softvérovej vrstve navyše.
Dve oddelené slučky namiesto jednej
Nástroj beží ako trvalá služba na pozadí (naštartuje sa pri každom prihlásení) a pozostáva z dvoch nezávislých slučiek:
- Sledovanie surových udev udalostí (USB, DRM, typec, thunderbolt pripojenia/odpojenia) s presnou časovou pečiatkou.
- Pravidelná kontrola pripojených monitorov — ale zapisuje sa len keď sa niečo skutočne zmení, nie pri každej kontrole.
Dôvod, prečo dve oddelené slučky namiesto jednej priamočiarej: pri jedinom zapojení dock-u prichádzajú desiatky udev udalostí naraz (každý port a rozhranie samostatne) — naviazať zápis priamo na každú z nich by log okamžite zaplavilo nepoužiteľným šumom. Kontrola stavu monitorov s porovnávaním voči predchádzajúcemu stavu rieši toto prirodzene — zaznamená sa skutočná zmena, nie každý medzikrok cestou k nej.
Referenčný "zdravý" priebeh
Nástroj bol naživo otestovaný počas vlastného vzniku — zapojenie dock-u počas písania skriptu zachytilo presný priebeh: monitory sa objavili v systéme, spočiatku bez priradeného rozlíšenia, o približne päť sekúnd neskôr sa doťahli na plné rozlíšenie. Celý proces od prvého signálu po tri plne funkčné monitory trval približne šesť sekúnd.
Tento zachytený priebeh teraz slúži ako referenčný, "zdravý" vzor. Keď sa nabudúce monitor zasekne v medzistave — viditeľný v systéme, ale bez priradeného rozlíšenia dlhšie než pár sekúnd — log to ukáže presne, namiesto toho, aby to bolo len subjektívny dojem "dnes to bolo pomalšie".
Druhý problém potrebuje iný typ dôkazu
Pre zaseknuté vypnutie/uspávanie potreboval byť dôkaz iného typu — nie priebežný log, ale spätný pohľad na to, čo sa dialo tesne pred koncom predchádzajúceho behu systému. Keďže perzistentný systémový žurnál je zapnutý, dá sa po tvrdom reštarte spätne prezrieť presne posledné momenty predchádzajúceho behu — typicky presne tam, kde niečo zablokovalo vypnutie ("A stop job is running for..."). Samostatný pomocný skript k tomu pridáva aj chvost logu zo sledovania dock-u z toho istého časového okna, aby sa dal stav dock-u v momente zaseknutia porovnať s tým, čo hovorí systémový žurnál.
Stav: čaká sa na dôkaz
Na rozdiel od ostatných článkov v tejto sérii tento nekončí vyriešeným bugom. Nástroj je nasadený a beží — čaká sa, kým sa jeden z pôvodných dvoch problémov znova náhodou stane, tentoraz s nástrojom pripraveným presne zachytiť, čo sa v tom momente deje.
A to je vlastne celý bod tohto článku: pri intermitentnom probléme je príprava na zachytenie dôkazu samostatný, plnohodnotný krok — nie odkladanie skutočnej práce. Kým nemáš spôsob, ako problém pri jeho výskyte zachytiť, akákoľvek oprava založená na dohade je len hádanie. Dobre postavený pozorovací nástroj niekedy predchádza samotnej oprave o dni či týždne — a to je v poriadku.
Čo si z toho odniesť
- Intermitentný problém sa nedá debugovať tak isto ako reprodukovateľný. Namiesto "spusti príkaz a pozri si výstup" treba niečo, čo beží nepretržite a čaká.
- Priebežný log a spätný pohľad do žurnálu sú dva rôzne nástroje pre dva rôzne typy problémov — jeden zachytáva postupný priebeh, druhý rekonštruuje posledné momenty pred zlyhaním.
- Referenčný "zdravý" priebeh má hodnotu sám osebe — bez neho nevieš spoznať, kedy je niečo skutočne pomalšie/inak, než by malo byť, iba to tušíš.
- Debounce/diff logika (zapisuj len zmenu, nie každú kontrolu) je nevyhnutná, keď zdroj eventov je hlučný — inak sa skutočný signál stratí v šume.
- Nevyriešený bug s dobrým pozorovacím nástrojom je lepší stav než nevyriešený bug bez neho. Príprava na zachytenie dôkazu je legitímny pokrok, aj keď sa problém sám ešte nevyriešil.
Riešite podobný problém?
Toto je presne typ práce, ktorú riešim aj pre iných — Linux servery, Docker nasadenia, zálohovanie a bezpečné nastavenie prístupu.
Pozrieť Linux & Docker služby