Logování chyb databáze
DB vrstva je navržena tak, aby aplikace nespadla při SQL chybách. Místo toho jsou chyby zaznamenávány a aplikace pokračuje v provozu. Toto je kriticky důležité chování, které je třeba pochopit pro ladění produkčních problémů.
Jak funguje logování
Měkké chyby (Soft Errors)
V produkční síti (když PRODUCTION konstanta je true):
- SQL chyba se zaloguje do
/var/log/db.error.log - Aplikace pokračuje bez přerušení (chyba se spustí jako
E_USER_WARNING) - Dotaz vrátí prázdné výsledky (
[],null, etc.)
Příklad:
// SELECT z neexistující tabulky v productionu
$users = DB::results("SELECT * FROM nonexistent_table");
// Výsledek: $users = []
// Chyba se zaloguje do /var/log/db.error.log
// Aplikace pokračuje
Tvrdé chyby (Development)
V lokálním vývoji (když PRODUCTION konstanta je false nebo nedefinovaná):
- SQL chyba se zaloguje do
/var/log/db.error.log - Následně se vyhodí
PDOException– aplikace se přeruší - Vývojář vidí stacktrace a může chybu opravit
Příklad:
// SELECT z neexistující tabulky v developmentu
$users = DB::results("SELECT * FROM nonexistent_table");
// Výsledek: Vyhozena PDOException
// Chyba se loguje PŘED vyhodením
// Vývojář vidí stacktrace a lokaci chyby
Soubory logu
/var/log/db.error.log – Všechny SQL chyby
Zaznamenává všechny chyby v SQL dotazech, bez ohledu na prostředí.
Obsah log záznamu:
2024-01-15 14:23:45 - SELECT * FROM nonexistent_table
-------
Affected rows: 0
-------
Last error: Table 'database.nonexistent_table' doesn't exist
=======
Interpretace:
- Timestamp – kdy se chyba stala
- Query – SQL dotaz, který selhal
- Affected rows – počet řádků ovlivněných (obvykle 0 u SELECT s chybou)
- Last error – podrobná chybová zpráva z MariaDB
/var/log/db.log – Logování dotazů (v připravě)
Tento soubor slouží k logování všech dotazů (ne jen chyb) – užitečné pro diagnostiku výkonu. Není nyní aktivní, ale je připraven pro budoucí snadné zapnutí.
Kontrola chyb v kódu
Přístup k poslední chybě
$user = DB::row("SELECT * FROM users WHERE id = ?", [$id]);
if (DB::$lastError) {
// Chyba se stala – zpracuj ji
echo "Chyba databáze: " . DB::$lastError;
// Log do svého systému
log_error(DB::$lastError);
} else {
// Vše OK – pracuj s výsledkem
echo "Jméno: " . $user->name;
}
Kontrola po INSERT/UPDATE/DELETE
$sql = "UPDATE users SET name = ? WHERE id = ?";
DB::query($sql, [$newName, $userId]);
if (DB::$lastError) {
// INSERT/UPDATE/DELETE selhalo
echo "Chyba při aktualizaci: " . DB::$lastError;
} else {
if (DB::$affectedRows > 0) {
echo "Aktualizován počet řádků: " . DB::$affectedRows;
} else {
echo "Žádné řádky nebyly aktualizovány (uživatel neexistuje?)";
}
}
Praktické příklady
Transakce s kontrolou chyb
Při provádění transakce je důležité sledovat chyby a případně provést rollback.
DB::beginTransaction();
$sql = "INSERT INTO orders (user_id, amount) VALUES (?, ?)";
DB::query($sql, [$userId, $amount]);
if (DB::$lastError) {
echo "Chyba při vložení objednávky: " . DB::$lastError;
DB::rollback();
return false;
}
$sql = "UPDATE users SET credits = credits - ? WHERE id = ?";
DB::query($sql, [$amount, $userId]);
if (DB::$lastError) {
echo "Chyba při odečtení kreditu: " . DB::$lastError;
DB::rollback();
return false;
}
DB::commit();
echo "Objednávka byla úspěšně vytvořena";
return true;
Monitorování v produkci
Kontrola log souborů
# Zobrazit poslední SQL chyby
tail -f /var/log/db.error.log
# Počet chyb za poslední hodinu
grep "$(date +'%Y-%m-%d %H')" /var/log/db.error.log | wc -l
# Nejčastější chyby
grep "Last error:" /var/log/db.error.log | sort | uniq -c | sort -rn
Automatická notifikace
Doporučuje se monitorovat /var/log/db.error.log a upozornit tým, pokud počet chyb překročí určitou hranici. Například:
function checkDatabaseErrors(): void {
$errorLog = DIR . '/var/log/db.error.log';
$lastHour = time() - 3600;
if (!file_exists($errorLog)) {
return;
}
$lines = file($errorLog);
$recentErrors = array_filter($lines, function ($line) use ($lastHour) {
if (preg_match('/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2})/', $line, $matches)) {
return strtotime($matches[1]) >= $lastHour;
}
return false;
});
if (count($recentErrors) > 10) {
// Poslat alert: více než 10 chyb za poslední hodinu
sendAlert("Vysoký počet SQL chyb: " . count($recentErrors));
}
}
Důležité poznámky
Aplikace se neprolomí kvůli SQL chybě – to je záměrné, ale znamená to, že musíš vždy kontrolovat DB::$lastError v kritických operacích (vkládání plateb, mazání dat, atd.).
Vždy sleduj /var/log/db.error.log v productionu – i když se aplikace neprolomí, chyby se tam logují a mohou ukazovat na problémy se schématem, indexy, nebo přístupovými právy.
V developmentu vidíš chyby okamžitě – díky vyhazování PDOException v non-productionu. Využij to k ladění během vývoje.