CodeGym /Cours /SQL SELF /Logging automatique via des fonctions

Logging automatique via des fonctions

SQL SELF
Niveau 52 , Leçon 3
Disponible

Imagine que tu as lâché ton bot en roue libre sur la base de données pour qu’il fasse des opérations complexes. Tôt ou tard, il va trébucher, se planter ou tomber sur une situation chelou. Sans logging, il pourrait juste se taire et toi tu restes là à te demander ce qui a foiré. Le logging automatique aide à :

  • Suivre l’apparition des erreurs et des avertissements.
  • Comprendre la nature et les raisons des plantages.
  • Améliorer le debug et la perf du code.

Avec le logging automatique, tu crées une sorte de “boîte noire” qui enregistre les événements dans la base et t’aide à trouver les bugs, comme si t’étais un détective de ouf.

Comment mettre en place le logging automatique via des fonctions

  1. On définit une table pour les logs

Pour logger les erreurs, il nous faut un endroit où les stocker. On a déjà créé la table error_log dans la leçon précédente :

CREATE TABLE error_log (
    id SERIAL PRIMARY KEY,                 -- Identifiant unique de l’enregistrement
    error_message TEXT NOT NULL,          -- Message d’erreur
    error_time TIMESTAMP DEFAULT NOW(),   -- Date/heure de l’erreur
    function_name TEXT                    -- Nom de la fonction qui a déclenché l’erreur
);

Cette table a tout ce qu’il faut pour enregistrer les erreurs : le texte de l’erreur, la date/heure et la fonction d’où ça vient.

  1. On crée une fonction pour écrire dans les logs

Prochaine étape — créer une fonction universelle qui va écrire les erreurs dans la table error_log. Cette fonction sera appelée à chaque fois qu’on veut enregistrer une erreur.

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);
    -- Message de succès du logging
    RAISE NOTICE 'Erreur enregistrée : %', p_error_message;
END;
$$ LANGUAGE plpgsql;

Décryptons ce code :

  1. p_error_message et p_function_name — ce sont les paramètres de la fonction, ils prennent le message d’erreur et le nom de la fonction qui l’a appelée.
  2. INSERT INTO error_log ajoute l’enregistrement dans la table.
  3. RAISE NOTICE affiche un message dans la console pour que le dev soit au courant du logging.

Maintenant, on a réglé la première étape : on peut écrire les erreurs dans notre table sans se prendre la tête.

Utiliser la fonction log_error dans des cas concrets

Exemple 1 : Logger une erreur lors d’une division par zéro

On va créer une fonction qui fait une division simple, mais log l’erreur si le dénominateur vaut 0.

CREATE OR REPLACE FUNCTION divide_numbers(a NUMERIC, b NUMERIC)
RETURNS NUMERIC AS $$
DECLARE
    result NUMERIC;
BEGIN
    IF b = 0 THEN
        -- On appelle la fonction de logging
        PERFORM log_error('Tentative de division par zéro !', 'divide_numbers');
        -- On lève une exception
        RAISE EXCEPTION 'Division par zéro interdite.';
    END IF;

    -- On fait la division
    result := a / b;
    RETURN result;
END;
$$ LANGUAGE plpgsql;
  • Si le dénominateur vaut 0, la fonction log_error est appelée et écrit l’erreur dans la table.
  • Après avoir loggé l’erreur, on lève une exception avec RAISE EXCEPTION pour prévenir l’utilisateur.

Exemple d’appel :

SELECT divide_numbers(10, 0);

Résultat :

  • L’appel de cette fonction avec une division par zéro va écrire une erreur dans la table error_log.
  • L’utilisateur verra un message d’erreur dans sa console.

Exemple 2 : logging lors de l’insertion de données invalides

Regardons un exemple avec une fonction qui ajoute un nouvel étudiant dans la table students. Si le nom de l’étudiant est vide, on log l’événement et on arrête l’exécution.

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('Le nom de l’étudiant doit être renseigné !', 'add_student');
        RAISE EXCEPTION 'Le nom de l’étudiant ne peut pas être vide.';
    END IF;

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

Exemple d’appel :

SELECT add_student('');

Si on essaie d’ajouter un étudiant sans nom, la fonction va créer un enregistrement dans error_log avec le message approprié.

Exemple 3 : logging des avertissements

Pas besoin de toujours lever une exception pour l’utilisateur. Parfois, juste enregistrer un avertissement suffit. On va faire une fonction pour vérifier l’âge d’un étudiant :

CREATE OR REPLACE FUNCTION check_age(p_age INT)
RETURNS VOID AS $$
BEGIN
    IF p_age < 18 THEN
        -- On log un avertissement mais on n’arrête pas l’exécution
        PERFORM log_error('L’âge de l’étudiant est inférieur à 18.', 'check_age');
        RAISE NOTICE 'Avertissement : l’âge de l’étudiant est inférieur à 18.';
    END IF;

    RAISE NOTICE 'Contrôle d’âge réussi.';
END;
$$ LANGUAGE plpgsql;

Exemple d’appel :

SELECT check_age(16);

Résultat :

  • Un avertissement est enregistré dans la table error_log.
  • Un message s’affiche dans la console pour dire que l’âge de l’étudiant est inférieur à 18.

Logging et gestion des exceptions

On va combiner l’enregistrement des erreurs et la gestion des exceptions dans une fonction un peu plus costaud. Imagine qu’on doit recalculer les notes des étudiants dans la table grades. Si le process échoue pour un étudiant, l’erreur est loggée mais l’opération continue pour les autres.

CREATE OR REPLACE FUNCTION recalculate_grades()
RETURNS VOID AS $$
DECLARE
    student RECORD;
BEGIN
    FOR student IN SELECT * FROM students LOOP
        BEGIN
            -- Exemple de tâche : mise à jour des notes de l’étudiant
            UPDATE grades SET final_grade = final_grade + 1
            WHERE student_id = student.id;

            RAISE NOTICE 'Notes mises à jour pour l’étudiant %', student.name;
        EXCEPTION WHEN OTHERS THEN
            -- On log l’erreur et on continue
            PERFORM log_error('Impossible de mettre à jour les notes pour l’étudiant ' || student.name, 'recalculate_grades');
        END;
    END LOOP;
END;
$$ LANGUAGE plpgsql;

Exemple d’appel :

SELECT recalculate_grades();

Cette approche rend ta fonction beaucoup plus robuste, car les erreurs sont loggées séparément et n’arrêtent pas tout le traitement.

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