CodeGym /Kursy /SQL SELF /Automatyczne logowanie przez funkcje

Automatyczne logowanie przez funkcje

SQL SELF
Poziom 52 , Lekcja 3
Dostępny

Wyobraź sobie, że wysłałeś swojego bota na samodzielne pływanie po bazie danych, żeby robił skomplikowane operacje. Prędzej czy później potknie się, walnie babola albo natknie się na coś niespodziewanego. Bez logowania może po prostu zamilknąć, a Ty zostaniesz z pytaniem, co poszło nie tak. Automatyczne logowanie pomaga:

  • Śledzić pojawianie się błędów i ostrzeżeń.
  • Kumać naturę i przyczyny awarii.
  • Poprawiać diagnostykę i wydajność kodu.

Dzięki automatycznemu logowaniu tworzysz taki "czarny skrzynkę", która zapisuje zdarzenia w bazie i pomaga Ci wyłapywać błędy, jakbyś był pierwszorzędnym detektywem.

Tworzenie automatycznego logowania przez funkcje

  1. Definiujemy tabelę na logi

Żeby logować błędy, potrzebujemy miejsca na ich przechowywanie. Już wcześniej stworzyliśmy tabelę error_log w poprzednim wykładzie:

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- Unikalny identyfikator wpisu
    error_message TEXT NOT NULL,          -- Wiadomość o błędzie
    error_time TIMESTAMP DEFAULT NOW(),   -- Czas wystąpienia błędu
    function_name TEXT                    -- Nazwa funkcji, która wywołała błąd
);

Ta tabela ma wszystko, co trzeba do zapisywania błędów: tekst błędu, czas i funkcję, z której wyskoczył.

  1. Tworzymy funkcję do zapisywania logów

Kolejny krok — stworzyć uniwersalną funkcję, która będzie wrzucać błędy do tabeli error_log. Ta funkcja będzie wywoływana zawsze, gdy chcemy zarejestrować błąd.

CREATE OR REPLACE FUNCTION log_error(p_error_message TEXT, p_function_name TEXT)
RETURNS VOID AS $$
BEGIN
    INSERT INTO error_log (error_message, function_name)
    VALUES (p_error_message, p_function_name);
    -- Wiadomość o udanym logowaniu
    RAISE NOTICE 'Błąd zalogowany: %', p_error_message;
END;
$$ LANGUAGE plpgsql;

Rozkminiamy ten kod:

  1. p_error_message i p_function_name — parametry funkcji, które przyjmują wiadomość o błędzie i nazwę wywołującej funkcji.
  2. INSERT INTO error_log dodaje wpis do tabeli.
  3. RAISE NOTICE wyświetla info w konsoli, żeby programista wiedział, że logowanie działa.

Teraz mamy ogarnięte pierwsze zadanie: możemy wrzucać błędy do naszej tabeli praktycznie bez wysiłku.

Użycie funkcji log_error w realnych zadaniach

Przykład 1: Logowanie błędów przy dzieleniu przez zero

Stwórzmy funkcję, która robi proste dzielenie, ale loguje błąd, jeśli mianownik to 0.

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- Wywołujemy funkcję logowania
        PERFORM log_error('Próba dzielenia przez zero!', 'divide_numbers');
        -- Generujemy wyjątek
        RAISE EXCEPTION 'Dzielenie przez zero jest niedozwolone.';
    END IF;

    -- Wykonujemy dzielenie
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • Jeśli mianownik to 0, wywoływana jest funkcja log_error, która zapisuje błąd do tabeli.
  • Po zapisaniu błędu generowany jest wyjątek RAISE EXCEPTION, żeby użytkownik się dowiedział.

Przykład wywołania:

SELECT divide_numbers(10, 0);

Wynik:

  • Wywołanie tej funkcji z dzieleniem przez zero wrzuci błąd do tabeli error_log.
  • Użytkownik zobaczy komunikat o błędzie w swojej konsoli.

Przykład 2: logowanie przy wstawianiu nieprawidłowych danych

Weźmy przykład z funkcją, która dodaje nowego studenta do tabeli students. Jeśli imię studenta jest puste, logujemy zdarzenie i przerywamy wykonanie.

CREATE OR REPLACE FUNCTION add_student(p_name TEXT)
RETURNS VOID AS $$
BEGIN
    IF p_name IS NULL OR p_name = '' THEN
        PERFORM log_error('Imię studenta musi być podane!', 'add_student');
        RAISE EXCEPTION 'Imię studenta nie może być puste.';
    END IF;

    INSERT INTO students (name) VALUES (p_name);
END;
$$ LANGUAGE plpgsql;

Przykład wywołania:

SELECT add_student('');

Jeśli spróbujemy dodać studenta bez imienia, funkcja stworzy wpis w error_log z odpowiednią wiadomością.

Przykład 3: logowanie ostrzeżeń

Nie zawsze trzeba rzucać wyjątek użytkownikowi. Czasem wystarczy zarejestrować ostrzeżenie. Zróbmy funkcję do sprawdzania wieku studenta:

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- Logujemy ostrzeżenie, ale nie przerywamy wykonania
        PERFORM log_error('Wiek studenta jest poniżej 18.', 'check_age');
        RAISE NOTICE 'Ostrzeżenie: wiek studenta jest poniżej 18.';
    END IF;

    RAISE NOTICE 'Sprawdzanie wieku zaliczone.';
END;
$$ LANGUAGE plpgsql;

Przykład wywołania:

SELECT check_age(16);

Wynik:

  • Wpis ostrzeżenia w tabeli error_log.
  • Powiadomienie w konsoli, że wiek studenta jest poniżej 18.

Logowanie i obsługa wyjątków

Połączmy teraz zapisywanie błędów i obsługę wyjątków w bardziej złożonej funkcji. Wyobraź sobie, że mamy zadanie przeliczyć oceny studentów w tabeli grades. Jeśli proces nie pójdzie dla któregoś studenta, błąd jest logowany, ale operacja leci dalej.

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- Przykład zadania: aktualizacja ocen studenta
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE 'Zaktualizowano oceny dla studenta %', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- Logujemy błąd i lecimy dalej
            PERFORM log_error('Nie udało się zaktualizować ocen dla studenta ' || student.name, 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Przykład wywołania:

SELECT recalculate_grades();

To podejście sprawia, że Twoja funkcja jest dużo bardziej odporna, bo błędy są logowane osobno i nie zatrzymują działania na wszystkich danych.

Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION