Remontée d'exceptions
La remontée d'exceptions est le cœur du SDK. Une fois configuré, chaque exception que Laravel reporte est transmise à votre dashboard.
Capture automatique
Au démarrage, le SDK enregistre un callback reportable() additif sur le handler d'exceptions de l'application :
Comme le callback est additif, il ne remplace ni ne supprime votre logging existant ni les autres handlers reportable, il se contente d'en transmettre une copie à Quiet Guard. Toute exception qui atteint le handler (exceptions non capturées, ou tout ce que vous passez à report()) est capturée, à l'exception de celle levée en servant une requête qui correspond à ignore_paths : voir Configuration.
La capture est fail-safe : une panne réseau, une mauvaise configuration ou une erreur serveur dans le SDK est avalée et ne remonte jamais vers l'application hôte.
Fail-safe ne veut pas dire muet. Lorsque le serveur refuse un rapport, il dit pourquoi, et cette phrase est écrite dans votre propre log comme avertissement, sous la forme HTTP <statut> from <url>: <message> : un 402 pendant une relance de paiement, un 403 sur une limite de forfait, un 422 sur un champ mal formé. La ligne porte un marqueur interne, elle n'est donc jamais capturée puis transmise à son tour.
Remontée manuelle
Utilisez la façade Monitor pour reporter explicitement une exception gérée :
Monitor::report() ne lève jamais d'exception. Il ne fait silencieusement rien lorsque la remontée est désactivée, lorsque la clé du projet est absente, lorsque l'environnement courant n'est pas dans la liste blanche, ou lorsque la requête correspond à ignore_paths. À partir de la version 0.3.1, une MONITOR_URL vide ne l'arrête pas : elle vaut le service hébergé, voir Configuration.
Vous pouvez résoudre le même objet depuis le conteneur :
Ce qui est envoyé
Chaque rapport est posté sur l'endpoint /api/v1/ingest du serveur et contient :
L'exception
- classe, message, code, fichier et ligne ;
- la pile d'appels complète par défaut (
MONITOR_TRACE_LIMIT=0): chaque frame, pour que les erreurs profondes gardent leur origine ; fixez un nombre de frames pour alléger les payloads. Chaque frame est réduit àfile,line,function,classettype(les arguments ne sont jamais envoyés, ils peuvent contenir des secrets) ; - à partir de la version 0.3, le site de levée en tête de la pile : le fichier et la ligne de l'exception elle-même voyagent comme frame zéro, puisque la trace de PHP commence à l'appelant et n'a jamais contenu la ligne fautive.
MONITOR_TRACE_LIMITcompte cette frame (1= le site seul) ; - un extrait de code (
code) sur les frames de votre application : les cinq lignes de part et d'autre de la ligne de la frame, lues dans le fichier qui a tourné, chacune coupée à 500 caractères, sur au plus dix frames par rapport. Les frames d'une dépendance (tout chemin contenant/vendor/) n'en portent jamais. Une ligne qui nomme une clé de la listescrubci-dessous (password,secret,token,passphrase...) et lui donne une valeur ($secret = ...,'api_key' => ...,setApiKey('...')) est remplacée entière par[scrubbed], parce que le code source est l'endroit où vit un secret codé en dur ; les motskey,auth,credential,salt,private,dsn,bearer,sk_etpk_comptent aussi, et une valeur qui n'en nomme aucun voyage telle quelle. À partir de la version 0.3.1, un appel statique (Auth::user()) n'est plus pris pour une valeur, si bien que sa ligne reste lisible ; la règle entière est sur la page de masquage du cœur.MONITOR_CODE_SNIPPETS=falsen'envoie que le fichier et la ligne.
Le contexte
environment,release(depuisMONITOR_RELEASE, ou détectée depuis le checkout quand elle est vide),php_version,laravel_version,occurred_at(ISO 8601) ;source:consoleen CLI/file, ouhttppour les requêtes web.
Pour les requêtes HTTP, le contexte inclut en plus :
url: l'adresse complète de la requête. À partir de la version 0.3.1, elle passe au masquage : la valeur de chaque paramètre de sa chaîne de requête nommé dans la listescrub(letokenet lasignatured'un lien de réinitialisation signé), et tout segment de chemin fait de quarante lettres ou chiffres d'affilée (le jeton que Laravel place dans/reset-password/{token}), deviennent%5Bscrubbed%5D; un identifiant numérique, un slug, un UUID ou un ULID restent ;method;request: en-têtes, query string et corps: lepassword/password_confirmationdu corps étant retirés et l'ensemble passé au masquage. À partir de la version 0.3.1, le masquage entre aussi dans une valeur qui est un objet JSON écrit en chaîne, comme l'instantané (snapshot) qu'un composant Livewire renvoie à chaque requête, et un en-tête écrit avec des tirets est masqué comme son nom à soulignés :php_auth_pwmasquephp-auth-pw, le mot de passe d'une requête HTTP Basic ;user: uniquement l'identifiant de l'utilisateur authentifié (id), jamais ses attributs.
Limites appliquées avant l'envoi
L'endpoint d'ingestion valide quatre de ces champs et répond 422 pour le rapport entier dès que l'un d'eux est trop long. Le SDK les tronque donc lui-même plutôt que de perdre le rapport, et marque la coupe par … [truncated] :
| Champ | Limite |
|---|---|
exception.message | 8192 caractères |
exception.class | 255 caractères |
exception.file | 1024 caractères |
context.release | 255 caractères |
Ces limites sont atteintes précisément par les rapports que vous voulez le plus lire : une QueryException porte toute la requête SQL et ses bindings dans son message, et une exception levée depuis une classe anonyme a le chemin absolu du fichier dans son nom de classe, ce qui sur un répertoire de release consomme l'essentiel des 255 à lui seul. Tronquer est une réponse avec perte, et c'est la bonne ici : les 8192 premiers caractères d'une requête valent incomparablement mieux qu'un rapport qui disparaît en silence. La coupe compte des caractères et non des octets, si bien qu'un caractère multi-octets n'est jamais coupé en deux, ce qui produirait une charge que le serveur refuserait comme UTF-8 invalide.
Masquage
Avant que toute charge utile ne quitte l'application, les données de requête et de contexte sont masquées récursivement : toute clé dont le nom contient l'un des termes configurés (insensible à la casse) voit sa valeur remplacée par [scrubbed]. À partir de la version 0.3.1, le masquage lit aussi les chaînes qui portent elles-mêmes des valeurs nommées : une chaîne JSON est ouverte et masquée par clé, et une URL perd la valeur de ses paramètres nommés dans la liste ainsi que ses segments de chemin en forme de jeton (voir la page de masquage du cœur).
Les termes par défaut sont :
Pour ajouter les vôtres, publiez la config (php artisan vendor:publish --tag=monitor-config) et étendez le tableau scrub dans config/monitor.php :
Conservez chaque terme livré, sauf à vouloir l'enlever. Réécrire le tableau à la main, c'est ainsi que passphrase et les en-têtes d'IP visiteur disparaissent de la liste sans bruit.
La correspondance se fait par sous-chaîne : api_key masque donc aussi stripe_api_key, et token masque csrf_token. À partir de la version 0.3.1, un tiret y vaut un souligné : api_key masque aussi l'en-tête x-api-key.
Masquage par forme de la valeur
La liste scrub ci-dessus regarde le nom du champ. Elle ne voit pas une adresse écrite au milieu d'un message d'erreur, dans un segment d'URL, ou dans un champ que quelqu'un a appelé reference.
La liste redact regarde la valeur elle-même, sur votre serveur, avant tout envoi :
Les formes qui portent une clé de contrôle sont vérifiées et non simplement reconnues : une référence de commande à seize chiffres n'est pas prise pour un numéro de carte, et un IBAN doit passer le modulo 97. Chaque valeur masquée indique ce qui a été caché, par exemple Utilisateur [redacted:email] introuvable, de sorte que le message reste lisible.
Retirez les motifs qui produisent des faux positifs sur vos données, ou mettez 'redact' => [] pour tout désactiver. Pour vos propres formes :
Envoi en arrière-plan
Lorsque MONITOR_QUEUE est défini, les exceptions sont dispatchées comme job en file SendExceptionToMonitor (2 tentatives) au lieu d'être envoyées en ligne. Cela sort la remontée du chemin critique de la requête. Voir Configuration.
La charge est masquée avant d'être mise en file, si bien que les formes que le masquage ci-dessus existe pour arrêter ne séjournent jamais en clair dans vos propres tables jobs et failed_jobs. Un job dont l'envoi a échoué lève, en portant ce que le serveur a dit : la seconde tentative a donc réellement lieu, et un échec définitif est enregistré dans failed_jobs au lieu d'être marqué comme réussi.
Regroupement côté serveur
Le SDK ne fait qu'envoyer les données ; le serveur regroupe les occurrences en anomalies par empreinte, rouvre les régressions et corrèle les releases aux commits. Consultez la documentation du serveur pour la manière dont les anomalies sont affichées et gérées.
Vous lisez la documentation Laravel SDK v1.0.