Skip to content

Journal d'erreurs

Audience

Cet article s'adresse aux opérateurs de la plateforme GCM. Les administrateurs d'église devraient consulter l'article sur le journal d'audit dans Utilisateurs et rôles pour les changements qu'ils peuvent enquêter eux-mêmes — le Journal d'erreurs est à l'échelle de la plateforme et inclut les traces d'appel et les corps de requête, qui sont réservés au personnel GCM par conception.

L'onglet Journal d'erreurs (/platform/error-log) est la file de triage centrale pour tout ce qui explose n'importe où dans le système. Exceptions frontend capturées par la limite Sentry, fonctions edge qui lancent, routes API Vercel qui renvoient 500 et triggers de base de données qui lèvent — tout converge dans platform_error_log et émerge ici, filtrable par source, gravité, organisation et état résolu, auto-rafraîchi toutes les 30 secondes.

Journal d'erreurs avec filtres et panneau de détails

Les cinq sources

Chaque ligne porte une énumération source. La liste déroulante du filtre vous permet de restreindre à une à la fois :

  • Frontend — exceptions React non capturées. Captures par la limite d'erreur globale et postées via /api/log-error. Les champs url et user_agent sont remplis.
  • Fonction edge — fonctions edge Deno qui ont lancé ou appelé log() avec gravité error. La colonne function_name est définie.
  • API Vercel — fonctions serverless Node (les routes /api/*). Comme les fonctions edge mais avec le contexte du runtime Vercel.
  • Trigger DB — levé depuis l'intérieur de Postgres, généralement par un RAISE EXCEPTION dans un trigger. La trace d'appel est le contexte d'erreur Postgres.
  • Manuel — tout ce pour quoi log_error a été appelé explicitement. Utilisé pour les avertissements non fatals qui méritent d'être affichés.

Gravité

Trois niveaux, tous codés par couleur :

  • warning — ambre. Pas de requêtes en échec, mais assez bruyantes pour enquêter. Refus RLS, requêtes lentes, appels de passerelle retentés.
  • error — rose. Une requête a échoué. L'utilisateur a vu quelque chose de cassé.
  • fatal — rouge foncé. Une requête a échoué d'une manière qui a laissé l'état incohérent. À traiter comme page un.

Le filtre par défaut est "non résolu"

La page se charge avec resolved = false afin que la file soit ce qui est ouvert. Basculez sur Résolu pour voir l'historique trié, ou Tout pour une vue complète. Le filtre Organisation a une option spéciale Non attribué (pas d'organisation) pour les lignes qui se sont déclenchées avant qu'un contexte de locataire ne soit établi (le cas le plus courant pour les erreurs au démarrage du frontend).

La recherche textuelle frappe quatre colonnes à la fois : message, function_name, url, error_code. À utiliser comme vous utiliseriez la recherche Sentry — correspondance partielle, insensible à la casse.

À quoi ressemble une ligne

Chaque ligne du tableau affiche :

  • Quand — relatif ("il y a 3 min"). Survolez pour l'horodatage complet.
  • Source — icône colorée + étiquette.
  • Gravité — pastille.
  • Organisation — dérivée de context.org_name quand présent, sinon les 8 premiers caractères de organization_id, sinon un tiret.
  • Message — le message d'erreur, tronqué.
  • function_name si disponible, sinon url.
  • Statut — Ouvert ou Résolu.

Cliquez sur n'importe quelle ligne pour ouvrir la boîte de dialogue de détails.

La boîte de dialogue de détails

La boîte de dialogue de détails est l'espace de triage. La moitié supérieure est une grille clé/valeur : fonction / URL, code d'erreur, utilisateur (nom + e-mail), organisation + plan, les rôles qu'il avait, s'il était administrateur de plateforme à l'époque, route, contexte d'action, id de corrélation, user agent.

Deux sections repliables suivent :

  • Trace d'appel — la trace brute du runtime. Pour les triggers DB, c'est le contexte d'erreur Postgres. Pour les erreurs frontend, c'est la trace JS, source-mappée quand possible.
  • Contexte (complet) — la colonne JSONB context entière joliment imprimée. C'est là que les fonctions edge planquent les corps de requête, les paramètres de requête et les valeurs intermédiaires. Traitez-la comme sensible — elle peut inclure des e-mails et des ID.

PII dans le contexte

La colonne context n'est pas caviardée. C'est un déversement brut de ce que le code défaillant a capturé. Ne la collez pas dans Slack, dans un ticket public, ou dans un problème Sentry. Le Journal d'erreurs vit derrière la porte d'administrateur de plateforme précisément pour que cela soit sûr.

Résoudre une ligne

Le bas de la boîte de dialogue contient les contrôles de résolution :

  • Marquer comme résolu — capture une note optionnelle ("corrigé dans #123" ou "transitoire, ignoré") et imprime resolved, resolved_at, resolved_by, resolved_note. La ligne sort de la vue non résolue par défaut.
  • Rouvrir — visible uniquement sur les lignes déjà résolues. Efface les colonnes de résolution.
  • Supprimer — destructif. Supprime la seule ligne entièrement. Utile pour les expositions de données personnelles qui ne devraient pas rester dans la base de données.

La résolution est un signal de workflow, pas une correction. Marquer une ligne comme résolue n'arrête pas le bogue sous-jacent — cela dit juste à votre futur vous que l'erreur a été triée.

Actions en masse

Deux opérations en masse vivent dans l'en-tête du tableau :

Purger résolus > 30j

Supprime définitivement les lignes résolues de plus de 30 jours. C'est le balayage de conservation — une ligne triée ne mérite pas de loyer au-delà d'un mois. Économique à exécuter, sûr à exécuter régulièrement. Le bouton rapporte le nombre qu'il a retiré.

Effacer filtré

Supprime chaque ligne correspondant au filtre actuel. C'est dangereux et l'interface le sait :

  • Le bouton est désactivé tant qu'au moins un filtre ne restreint pas l'ensemble. Sans filtre, la mention "correspondant aux filtres actuels" de la boîte de dialogue serait un mensonge.
  • La boîte de dialogue de confirmation montre le nombre exact qu'elle supprimera.

Utilisez ceci pour effacer une classe bruyante d'avertissements après avoir livré la correction : filtrez sur source = frontend, message = ChunkLoadError, resolved = non résolu, appuyez sur Effacer, regardez le compte tomber à zéro.

Ce que signifie l'auto-rafraîchissement

La requête refait l'appel toutes les 30 secondes via le refetchInterval de React Query. Le spinner de chargement apparaît en ligne à côté du nombre de lignes à chaque nouvelle récupération — s'il tourne indéfiniment, le réseau est bloqué et les lignes existantes sont obsolètes. Le bouton Rafraîchir force une invalidation immédiate.

Patrons courants

Un pic d'avertissements EDGE_FUNCTION depuis une organisation — généralement un webhook mal configuré qui martèle un endpoint qui renvoie 429. Ouvrez l'organisation et vérifiez ses lignes channels.

Erreurs fatales sans organisation — la défaillance s'est produite avant que le contexte du locataire ne soit résolu. Les plantages au démarrage du frontend, les ratés d'auth-hook et les échecs de démarrage à froid des fonctions edge se regroupent ici. Regroupez par message et la cause est généralement une variable d'env manquante.

Erreurs de refus RLS depuis db_trigger — quelqu'un appelle une requête sans le bon rôle. Croisez l'id utilisateur dans context avec le journal d'audit pour voir ce qu'il essayait de faire.

Si une seule ligne nécessite une enquête par un ingénieur qui n'est pas administrateur de plateforme, copiez le correlation_id et partagez-le — il peut grep les journaux de fonction edge dans Supabase pour le même id sans que vous ayez à lui transférer la ligne.