Votre application est utilisée quotidiennement par des centaines de personnes, tout semble se dérouler normalement quand subitement l'un de vos utilisateurs vous signale une erreur.
Ni une ni deux vous plongez dans votre fichier de log pour comprendre ce qu'il vient de se passer... et vous vous retrouvez face à plusieurs milliers de lignes.
Difficile de retrouver l'erreur incriminée dans ces conditions.
Depuis Laravel 8.49, le framework offre la possibilité d'ajouter un context
unique à chaque ligne de log pouvant vous aider à identifier les erreurs d'un utilisateur précis.
Voyons comment utiliser cette feature pour traquer les erreurs d'un utilisateur dans une application Laravel 9 !
Basic usage
Le contexte doit être configuré en amont de l'utilisation des méthodes de logging (info, success, warning ...) depuis la méthode withContext()
de la class Illuminate\Log\Logger
.
1app(Logger::class)->withContext([2 'id' => '123456',3]);
Dès lors, quand vous utiliserez une méthode de logging cet identifiant sera automatiquement ajouté en suffixe à chaque ligne de votre fichier de logs.
1app(Logger::class)->error('Operations error');
Si vous utilisez le disk par défaut, cette ligne de log arrivera dans le fichier laravel.log
:
1// storage/logs/laravel.log2[2022-04-30 20:02:02] local.ERROR: Operations error {"id":"123456"}
Voyons désormais comment utiliser ce contexte pour traquer les logs d'un utilisateur !
tips, Il est possible d'annuler tous les contextes en cours grace à la méthode
withoutContext
duLogger
Un cas concret
Imaginez que vous développez une API ouverte.
Quand l'un de vos utilisateurs lève une exception vous voulez être en mesure de lui fournir l'identifiant unique de sa requête — cela lui permettra de vous le transmettre ultérieurement pour simplifier l'identification de son anomalie.
C'est un use-case relativement commun pour les API tiers permettant de faciliter l'exploitation des erreurs.
Le principe est assez simple, créer un middleware pour configurer le contexte tout en conservant l'identifiant unique dans les headers de la request, puis afficher l'identifiant à l'utilisateur au besoin.
Le middleware
Pour commencer il est nécessaire de créer un nouveau middleware que vous pouvez nommer AssignRequestId
.
1<?php 2 3namespace App\Http\Middleware; 4 5use Closure; 6use Illuminate\Log\Logger; 7use Illuminate\Support\Str; 8 9class AssignRequestId10{11 public function handle($request, Closure $next)12 {13 $requestId = (string) Str::uuid();14 15 app(Logger::class)->withContext([16 'request-id' => $requestId,17 ]);18 19 $request->headers->set('Request-Id', $requestId);20 21 return $next($request);22 }23}
La variable $requestId
provient d'un uuid
pour garantir son unicité puis est transmise au Logger
.
Pour finir nous ajoutons dans les headers de la request la valeur du $requestId
pour pouvoir le récupérer plus tard.
Dorénavant, chaque requête entrant dans votre Laravel aura un identifiant unique dans ses headers et tous les logs que vous effectuerez auront un suffixe request-id
avec la valeur de l'uuid !
N'oubliez pas, un middleware doit être renseigné dans le fichier
app\Http\Kernel.php
!
Logger et afficher le Request-Id
L'utilisateur génère une erreur, par exemple en ne répondant pas aux rules d'une FormRequest.
1// @Illuminate\Contracts\Validation\Validator2throw new WhateverException($validator->errors());
Profitons des méthodes report
et render
d'une exception pour factoriser ça proprement.
1<?php 2 3namespace App\Exceptions; 4 5use Exception; 6use Illuminate\Log\Logger; 7use Illuminate\Support\MessageBag; 8 9class WhateverException extends Exception10{11 public function __construct(12 protected MessageBag $messageBag,13 ){}14 15 public function report()16 {17 app(Logger::class)18 ->error([19 request()->getRequestUri(),20 $this->messageBag->toJson(),21 ]);22 }23 24 public function render()25 {26 return response()->json([27 'message' => 'It looks broken !',28 'request-id' => request()->header('Request-Id'),29 ], 400);30 }31}
L'utilisateur voit apparaitre sur son écran son request-id ainsi qu'un court message et vos logs contiennent désormais une nouvelle ligne associée à son identifiant !
1[2022-04-30 20:02:02] local.ERROR: array (2 0 => '/api/clips/1/show?relations=qsdsqdsqdsqdsq',3 1 => '{"relations":["The selected relations is invalid."]}',4) {"request-id":"397c2091-4275-455d-9bb8-05f942420cbf"}
Félicitations, vous pouvez désormais traquer vos utilisateurs ! 🧐
A lire
Autres articles de la même catégorie
Comment développer un paquet en local ?
Vous souhaitez ajouter une fonctionnalité à votre application via un paquet ? Voici un tour d’horizon de la phase de développement.
William Suppo
Les bases 3/6 : Création des vues
Découverte du moteur de vue Blade
William Suppo
Les bases 5/6 : Contrôle d’accès
Découverte du contrôle des accès de nos utilisateurs à travers les Policies.
William Suppo