8. diel - SDL - ERROR a logovanie
V dnešnom diele sa pozrieme na zachytávanie + errorov, ktoré SDL môže vyvolať a na ich následné logovanie. Rovnakým spôsobom môžeme samozrejme logovať aj akékoľvek ďalšie informácie.
ERROR
Pretože je SDL určené pre jazky C, nepracuje s výnimkami, ako to poznáme z C ++. To sa zmení, akonáhle použijeme objektový wrapper pre C ++. Do tej doby sa ale budeme musieť naučiť, ako pracovať s error v samotnom SDL.
Konvencie je relatívne jednoduchá. Pokiaľ sa jedná o funkciu, ktorá
niečo vytvára (SDL_CreateRGBSurface
,
SDL_CreateWindow
a iné), SDL vráti NULL
. Všetky
ostatné funkcie, vrátane napríklad SDL_Init
, vracia 0 pri
úspešnom vykonaní funkcie, v iných prípadoch vracia zápornú hodnotu. Je
potreba po každej takejto operácii overiť, či funkcia prebehla v poriadku.
Pokiaľ si nie sme istí, čo bude funkcia vracať, zistíme to v dokumentácii.
K samotnému získanie informácie o probléme, ktorý nastal, slúži
funkcia SDL_GetError. Tá vracia const char *
, teda
reťazec obsahujúci bližšie určenie chyby. Tento text je vždy v
angličtine. Po vyriešení ERROR by mala nasledovať funkcie SDL_ClearError,
ktorá vyčistí vložený error. SDL_GetError
po zavolaní tejto
metódy (alebo keď nie je žiadny error) vráti prázdny reťazec. Nie je to
však nutné, pretože pri ďalšom Error SDL premaže text pôvodného.
Posledný funkcia, ktorá sa u práce s error vyskytne, je SDL_SetError. Tá nastaví chybovú hlášku na reťazec, ktorý odovzdáme v parametri. Vzhľadom k tomu, že pracujeme v C ++, nebudeme túto funkciu využívať, pretože by tieto stavy mali byť vyriešené výnimkami. Ako som už spomenul, pridaním ďalšieho error sa predchádzajúce zmaže, to isté platí aj pre túto funkciu. Tiež pozor na návratovú hodnotu, tá je vždy -1.
Logy
Pri logovanie už je situácia o niečo pestrejšia. Logovanie pracuje s
rôznymi prioritami a kategóriami. Najskôr si popíšeme jednotlivé
kategórie a následne funkcie, ktoré SDL pre logovanie poskytuje. Logovanie sa
tiež na každom OS chová odlišne. Na systémoch Windows sa bude logovať do
debug výstupu (nie je ho teda možné použiť pre produkciu). Na systémoch
Android bude výstup do klasického logovacieho výstupu. Na všetkých
zostávajúcich systémoch sa budú logami zapisovať to štandardného error
výstupu. Pre C ++ je to teda sderr
. Tiež je potrebné dať pozor
na dĺžku správy. Správa, ktorá má viac ako 4096 bajtov (4096 znakov), bude
automaticky orezaná.
Kategórie
Jednotlivé kategórie logov sú vypísané v dokumentácii.
- Aplication log je log týkajúce sa aplikácie. Môžeme u neho vypisovať logami oblasti štartu a vypnutie aplikácie, načítanie konfigurácie a podobné veci.
- Error log je log týkajúce sa problémov v aplikácii.
Spravidla sa sem zaraďujú správy, ktoré sme dostali z
SDL_GetError
. - Do systémového logu zapisujeme informácie, ktoré sa týkajú priamo systému. Môžeme tu napríklad zapísať informácie o hardvéri počítača a informácie pochádzajúce z operačného systému. Prečo sa nám tieto informácie hodí? Ak niekto bude našu aplikáciu používať na jeho stroji a niečo nebude fungovať, je vhodné mať aspoň nejaké informácie o stroji, na ktorom aplikácia beží.
- Audio a Video logami slúži na informovanie o funkcii videá a audia. Môžeme tu napríklad vypísať, v akom rozlíšení bola vytvorená textúra alebo okno.
- Ďalším logom je render log. Ten bude spravidla v
blízkosti renderovací funkcie v nekonečnej slučke (pozri predchádzajúce
kapitoly). Ideálne by mal byť tento log za každú funkcií, ktorá niečo
vykresľuje (
SDL_RenderCopy
,SDL_RenderClear
a iné). - Posledné prichystanú kategórií použiteľnú v aplikácii je input log, ktorý loguje informácie prúdiacej do aplikácie. Môžeme tu napríklad vypisovať, ktorú akciu užívateľ vykonal.
- Okrem toho má SDL ďalšie dve kategórie, ktoré využijeme predovšetkým pri debugovania. Je to test a Assert log. Typickým príkladom sú testy aplikácie.
Poslednou kategóriou je custom log, ktorému môžeme
priradiť čokoľvek. Spravidla si vytvárame vlastné kategórie, ktoré
aplikácie potrebuje. Ak chceme tieto kategórie vytvoriť, napíšeme si
vlastný Enumerátor, ale prvé hodnota musí byť rovnaká s
SDL_LOG_CATEGORY_CUSTOM
, aby nenastala kolízie s ostatnými
kategóriami. Ako vytvoriť vlastnú kategóriu vidíme na nasledujúcom
kóde.
enum
{
MOJEAPLIKACE_CATEGORY_KATEGORIE1 = SDL_LOG_CATEGORY_CUSTOM,
MOJEAPLIKACE _CATEGORY_KATEGORIE2,
MOJEAPLIKACE _CATEGORY_KATEGORIE3,
...
};
Nie je nutne pravidlom, že musí byť použitá vždy presná kategórie. SDL pri logovanie jednotlivé kategórie nerozlišuje, je teda jedno, pod akou kategóriou informáciu zalogujeme. Kategória sa nám môžu hodiť neskôr, až si budeme vytvárať vlastné logovacie funkciu. Tá môže jednotlivé kategórie rozlišovať a správať sa pre nich rozdielne. Vlastné logovacie funkciu budem popisovať ďalej v článku.
Priority
Každý log tiež môže mať vlastné priority. Prioritou bližšie popíšeme, aká dôležitá je informácia, ktorú logu. Priority budem popisovať vzostupne podľa dôležitosti:
- Verbose - v preklade niečo ako ukecaný. Pod touto prioritou si môžeme vypisovať ľubovoľné informácie. Môžeme vypisovať text, aby sme vedeli, na ktorom mieste programu sme. Väčšinu problémov riešených touto prioritou možno riešiť debuggerom.
- Debug - pod touto prioritou budeme vypisovať informácie týkajúce sa debugovania. Môžeme vypisovať hodnoty premenných, ktoré nás zaujímajú, vypisovať aktuálny stav na určitom mieste programu a pod. Tieto problémy by sme mali opäť riešiť debuggerom.
- Info - tu začínajú užitočnejšie priority, ktoré môžeme použiť v aplikácii. Pod info prioritou môžeme zverejňovať informácie, ktoré budú mať len informačný charakter. Napríklad "zapnutie aplikácie" alebo "načítanie konfigurácie". Ak budeme chcieť neskôr z logu zistiť, čo sa u používateľa stalo, pomôže nám info k približnému určenie oblasti, v ktorej k problému došlo.
- Warn - priorita oznamujúce, že je pravdepodobne niečo v neporiadku. Pod touto prioritou budeme logovať informácie, ktoré sú mimo obvyklý chod aplikácie, ale nie sú dôležité do budúcnosti. Ak napríklad aplikácia bude chcieť načítať joystick, hoci ho nepoužíva (napríklad nie je v aktuálnom leveli potreba). Nie je to dôležitá súčasť systému, preto informáciu o tom, že sa nepodarilo načítať joystick, stačí označiť prioritou Warn.
- Error - priorita oznamujúce problém v aplikácii. Ide o
udalosť, ktorá priamo aplikáciu nevypne, ale spravidla je predzvesť konca.
Napríklad keď sa nám nepodarí vytvoriť
SDL_Surface
, aplikácia spadne až vo chvíli, keď sa pokúsime tentoSDL_Surface
použiť. V kóde kontroly, či bolSDL_Surface
vytvorený, môžeme zalogovať informáciu o probléme s prioritou error. - Critical - priorita spätá s kritickou situáciou v aplikácii. Ak sa vyskytne takáto udalosť, aplikácia spravidla nie je schopná pokračovať v práci. Takáto udalosť môže nastať napríklad keď sa nepodarí SDL inicializovať alebo vytvoriť okno. Po takýchto udalostiach nie je aplikácia schopná pokračovať a spadne alebo sa sama ukončí.
Logovanie
Najjednoduchšie funkcií pre logovanie je SDL_Log. Prijíma
reťazec v rovnakom formáte, aký je u funkcia printf
. V reťazci
prijíma zástupné znaky ako "% i", "% f" a iné. Ďalšie parametre funkcie
sú premenné, ktoré nahradia tieto zástupné znaky. Log sa touto funkciou
zapíše do kategórie application s prioritou
info.
Presným protikladom je funkcia SDL_LogMessage. Prvým parametrom je
kategória, ktorú chceme logovať, druhým parametrom je potom priorita, pod
ktorú budeme správu logovať. Tretím a štvrtým parametrom sú opäť
reťazec a premenné, ktoré chceme zalogovať. Tieto parametre sú zhodné s
parametrami SDL_Log
.
Logovanie s určenou prioritou
Každá priorita má vlastné funkciu, ktorá loguje správy. Napríklad
funkcia SDL_LogCritical zaloguje správu s prioritou
critical. Kategóriu opäť určíme prvým parametrom, zvyšok
parametrov je určený pre reťazec a premenné. Odporúčam používať tento
súbor funkcií, nie ž samotnú funkciu SDL_LogMessage
. Hoci je
výsledok rovnaký, použitím určené funkcie bude kód prehľadnejšie a
svojím spôsobom aj kratšie, pretože nemusíme vypisovať konštantu
priority. Zoznam funkcií je tu.
Nastavenie zobrazených logov
Vyššie v článku som povedal, že SDL jednotlivé kategórie pri výstupe nerozlišuje. Na čo teda slúži? Pre každú kategóriu môžeme nastaviť prioritu, ktorá sa zobrazí na výstupe. Ak nastavíme napríklad ku kategórii aplication prioritu info, budú sa logovať všetky informácie s prioritou info, warning, error a critical. Na nastavenie priority pre kategóriu slúži funkcia SDL_LogSetPriority. Priority s vyššou dôležitosťou ako je priorita zadaná (vrátane) sa budú logovať, ostatné na výstupe neuvidíme. Môžeme tiež nastaviť rovnakú prioritu pre všetky kategórie, a to funkciou SDL_SetAllPriority.
V predvolenom nastavení má application kategórie nastavenú prioritu info, Assert kategórie prioritu warn a test kategórie prioritu verbose. Všetky ostatné kategórie majú nastavenú prioritu critical. Ak priority zmeníme a budeme ich chcieť vrátiť do východiskovej hodnoty, poslúži nám funkcia SDL_LogResetAllPriorities.
Vlastný logovacie systém
SDL nám ponúka prostriedok, vďaka ktorému môžeme logovanie napojiť na vlastný logovacie systém, bez toho aby sme museli meniť už existujúcej aplikácie. Vystačíme si s jedinou funkciou, a to SDL_LogSetOutputFunction. Tá v prvom parametri prijíma callback, ktorý zavolá vždy, keď bude chcieť niečo zalogovať. V druhom parametra prijíma ukazovateľ na void, ktorý bude odovzdaný callbacku. Môžeme do neho vložiť triedu alebo štruktúru, ktorú budeme pri logovanie potrebovať. Musíme ale počítať s tým, že už túto triedu nemôžeme vymeniť za inú (bez znovu zavolanie funkcie). Callback nie je nič iné ako ukazovateľ na funkciu, ktorá vyzerá nasledovne.
void LogFunction(void* data, int kategorie, SDL_LogPriority priorita, const char* zprava);
Každá správa prejde cez túto funkciu, ktorá ju zaloguje (predvolený logovacie systém sa deaktivuje).
Ukážkový príklad
Ako ukážku si vezmeme príklad z minulej lekcie a doplníme do neho logovanie (každý sa môžete skúsiť zamyslieť, ako by to vyzeralo - moje riešenie si môžete stiahnuť pod článkom). Overíme každú funkciu, ktorú overiť môžeme a pokiaľ nastane problém, zalogujeme ho. Rovnakým spôsobom by mala byť postavená každá aplikácia. Aby sme videli, ako SDL loguje správy s rozdielnou kategórií a prioritou, vložím do programu pár logov, ktoré sa zalogují vždy.Všimnime si predovšetkým inicializačnej funkcie. Vidíme, že pre každú časť knižnice (SDL, TTF, IMG) sa kód líšia. Pre SDL vráti funkcie pri neúspechu zápornú hodnotu. IMG naopak pri úspechu vracia konštantu, ktorú sme odovzdali v parametri, a pri neúspechu 0. Je vždy nutné overiť v dokumentácii, ako funkcia reaguje na zlé parametre alebo prostredia.
To je pre dnešné lekciu všetko. V budúcom dieli sa pozrieme na časovač a na optimalizáciu FPS, teda snímok za sekundu tak, aby bola aplikácia čo najplynulejší a zároveň spotrebovala čo najmenej procesorového času.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 837x (9.58 MB)