CodeGym /Corsi /SQL SELF /Log automatico tramite funzioni

Log automatico tramite funzioni

SQL SELF
Livello 52, Lezione 3
Disponibile

Immagina di aver lasciato il tuo bot libero di girare nel database per fare operazioni complesse. Prima o poi inciampa, sbaglia o si trova davanti a una situazione inaspettata. Senza logging, potrebbe semplicemente zittirsi e tu rimani lì a chiederti cosa sia andato storto. Il logging automatico ti aiuta a:

  • Tracciare quando succedono errori e warning.
  • Capire la natura e le cause dei problemi.
  • Migliorare la diagnostica e la performance del codice.

Con il logging automatico crei una sorta di "scatola nera" che registra gli eventi nel database e ti aiuta a trovare i bug, come se fossi un vero detective.

Come creare il logging automatico tramite funzioni

  1. Definiamo una tabella per i log

Per loggare gli errori, ci serve un posto dove salvarli. Abbiamo già creato la tabella error_log nella lezione precedente:

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- Identificatore unico della riga
    error_message TEXT NOT NULL,           -- Messaggio di errore
    error_time TIMESTAMP DEFAULT NOW(),    -- Momento in cui è successo l'errore
    function_name TEXT                     -- Nome della funzione che ha causato l'errore
);

Questa tabella ha tutto quello che serve per registrare gli errori: testo dell'errore, quando è successo e la funzione da cui è partito.

  1. Creiamo una funzione per scrivere i log

Il prossimo step è creare una funzione universale che scrive gli errori nella tabella error_log. Questa funzione verrà chiamata ogni volta che vogliamo registrare un errore.

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);
    -- Messaggio di logging avvenuto con successo
    RAISE NOTICE 'Errore loggato: %', p_error_message;
END;
$$ LANGUAGE plpgsql;

Vediamo questo codice:

  1. p_error_message e p_function_name sono i parametri della funzione che ricevono il messaggio di errore e il nome della funzione chiamante.
  2. INSERT INTO error_log aggiunge una riga nella tabella.
  3. RAISE NOTICE stampa un messaggio in console così lo sviluppatore sa che il logging è avvenuto.

Ora abbiamo risolto il primo problema: possiamo scrivere errori nella nostra tabella con il minimo sforzo.

Usare la funzione log_error in casi reali

Esempio 1: Logging di errori nella divisione per zero

Creiamo una funzione che fa una semplice divisione, ma logga un errore se il denominatore è 0.

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- Chiamiamo la funzione di logging
        PERFORM log_error('Tentativo di divisione per zero!', 'divide_numbers');
        -- Generiamo un'eccezione
        RAISE EXCEPTION 'Divisione per zero non permessa.';
    END IF;

    -- Facciamo la divisione
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • Se il denominatore è 0, viene chiamata la funzione log_error che scrive l'errore nella tabella.
  • Dopo aver scritto l'errore, viene generata un'eccezione con RAISE EXCEPTION per avvisare l'utente.

Esempio di chiamata:

SELECT divide_numbers(10, 0);

Risultato:

  • Chiamando questa funzione con divisione per zero, l'errore viene scritto nella tabella error_log.
  • L'utente vede il messaggio di errore nella sua console.

Esempio 2: logging quando si inseriscono dati non validi

Vediamo un esempio con una funzione che aggiunge un nuovo studente nella tabella students. Se il nome dello studente è vuoto, logghiamo l'evento e interrompiamo l'esecuzione.

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('Il nome dello studente deve essere inserito!', 'add_student');
        RAISE EXCEPTION 'Il nome dello studente non può essere vuoto.';
    END IF;

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

Esempio di chiamata:

SELECT add_student('');

Se proviamo ad aggiungere uno studente senza nome, la funzione crea una riga in error_log con il messaggio giusto.

Esempio 3: logging di warning

Non sempre serve generare un'eccezione per l'utente. A volte basta registrare un warning. Facciamo una funzione che controlla l'età dello studente:

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- Logghiamo il warning ma non interrompiamo l'esecuzione
        PERFORM log_error('L\'età dello studente è sotto i 18.', 'check_age');
        RAISE NOTICE 'Attenzione: l\'età dello studente è sotto i 18.';
    END IF;

    RAISE NOTICE 'Controllo età superato.';
END;
$$ LANGUAGE plpgsql;

Esempio di chiamata:

SELECT check_age(16);

Risultato:

  • Registrazione del warning nella tabella error_log.
  • Notifica in console che l'età dello studente è sotto i 18.

Logging e gestione delle eccezioni

Mettiamo insieme la scrittura degli errori e la gestione delle eccezioni in una funzione più complessa. Immagina di dover ricalcolare i voti degli studenti nella tabella grades. Se il processo fallisce per uno studente, l'errore viene loggato ma l'operazione continua.

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- Esempio di task: aggiornamento dei voti dello studente
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE 'Voti aggiornati per lo studente %', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- Logghiamo l'errore e continuiamo
            PERFORM log_error('Impossibile aggiornare i voti per lo studente ' || student.name, 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Esempio di chiamata:

SELECT recalculate_grades();

Questo approccio rende la tua funzione molto più resistente, perché gli errori vengono loggati separatamente e non bloccano l'esecuzione su tutti i dati.

2
Compito
SQL SELF, livello 52, lezione 3
Bloccato
Log degli errori nei calcoli
Log degli errori nei calcoli
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION