Skip to content

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.