Wyobraź sobie sytuację, gdzie pracujesz z bazą danych, obsługujesz masę transakcji, ale coś poszło nie tak. Użytkownik narzeka, biznes krzyczy, a ty nawet nie widzisz, co dokładnie się wydarzyło. Właśnie tutaj wchodzi do gry poprawne logowanie błędów. Pozwala ono na:
- Przechowywanie błędów w bazie danych do późniejszej analizy.
- Łatwe odzyskiwanie szczegółów błędu: kiedy się pojawił, jaka była wiadomość i powiązane dane.
- Poprawianie swojego kodu, pracując nad typowymi błędami, które można wykryć analizując logi.
Krótko mówiąc, logowanie to jak nagranie z kamery monitoringu dla twojej bazy danych: widzisz wszystko, co poszło nie tak i kiedy to się wydarzyło.
Tworzymy tabelę error_log
Zacznijmy, jak to się mówi, od fundamentów. Musimy stworzyć tabelę, w której będziemy trzymać info o błędach. Tabela będzie miała następujące pola:
id— unikalny identyfikator błędu.error_message— tekst błędu.error_time— czas, kiedy wystąpił błąd.- (Opcjonalnie)
context— kontekst błędu, jeśli chcemy przechowywać szczegóły.
CREATE TABLE error_log (
id SERIAL PRIMARY KEY, -- Unikalny identyfikator błędu
error_message TEXT NOT NULL, -- Tekstowa wiadomość o błędzie
error_time TIMESTAMP NOT NULL DEFAULT NOW(), -- Czas wystąpienia błędu
context JSONB -- Dodatkowe dane o błędzie
);
Co się tutaj dzieje?
id SERIAL PRIMARY KEY— to pole tworzy automatycznie unikalny identyfikator dla każdego wpisu.error_message TEXT NOT NULL— tutaj będzie przechowywany tekst błędu. Pole obowiązkowe.error_time TIMESTAMP NOT NULL DEFAULT NOW()— pole rejestrujące czas zdarzenia. Jeśli nie podasz wartości, automatycznie zapisze aktualny czas dziękiDEFAULT NOW().context JSONB— opcjonalnie, do przechowywania dodatkowych informacji, np. danych o operacji, gdzie wystąpił błąd.
Po wykonaniu komendy CREATE TABLE w twojej bazie danych pojawi się struktura do przechowywania logów.
Przykład zapisu błędów do tabeli
Teraz, gdy tabela już jest, przejdźmy do praktyki: będziemy zapisywać info o błędach do tabeli. Napiszemy funkcję, która wrzuca tekst błędu i czas do error_log.
Przykład funkcji do zapisywania błędów
CREATE OR REPLACE FUNCTION log_error(p_error_message TEXT, p_context JSONB DEFAULT NULL)
RETURNS VOID AS $$
BEGIN
INSERT INTO error_log (error_message, context)
VALUES (p_error_message, p_context);
END;
$$ LANGUAGE plpgsql;
p_error_message— parametr wejściowy, gdzie przekazujesz tekst błędu.p_context— opcjonalny parametr do przekazania dodatkowych danych. Domyślnie przyjmujeNULL.INSERT INTO error_log (error_message, context)— dodaje nowy wpis do tabelierror_log.DEFAULT NULL— jeśli nie podasz kontekstu, pole będzieNULL.
Teraz, jeśli chcesz zapisać wiadomość o błędzie, możesz wywołać funkcję tak:
SELECT log_error('Błąd podczas wykonywania zapytania', '{"query": "SELECT * FROM data"}');
To doda nowy wpis do tabeli error_log.
Automatyczne logowanie błędów
Za każdym razem pisać SELECT log_error(...) ręcznie może być upierdliwe. Zautomatyzujmy ten proces używając obsługi wyjątków.
Przykład funkcji z obsługą wyjątków.
CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
result NUMERIC;
BEGIN
-- Spróbuj wykonać dzielenie
result := a / b;
-- Zwróć wynik
RETURN result;
EXCEPTION
WHEN division_by_zero THEN
-- Logujemy błąd i przekazujemy kontekst
PERFORM log_error('Dzielenie przez zero', jsonb_build_object('a', a, 'b', b));
-- Rzucamy wyjątek dla użytkownika
RAISE EXCEPTION 'Dzielenie % przez % niemożliwe — dzielnik jest zerem', a, b;
END;
$$ LANGUAGE plpgsql;
- Sprawdzenie dzielenia: wykonuje się
result := a / b. Jeślib = 0, PostgreSQL rzuca wyjątekdivision_by_zero. - Obsługa wyjątków (
EXCEPTION) przechwytuje błąd. - W środku obsługi wywołujemy funkcję
log_error, żeby zapisać błąd do tabeli razem z parametrami, które wywołały problem. - Po zapisaniu błędu przez
RAISE EXCEPTIONrzucamy nowe info o błędzie, żeby użytkownik też dostał powiadomienie.
Przykład wywołania:
SELECT divide_numbers(10, 0);
Wynik:
- Użytkownik zobaczy błąd:
Dzielenie 10 przez 0 niemożliwe — dzielnik jest zerem. - W tabeli
error_logpojawi się wpis o dzieleniu przez zero.
GO TO FULL VERSION