9.Créer un fichier de logs/traces

9.4.Loguer des messages avec Zend-Log

9.4.1.Introduction

zend-log n'est pas à l'origine un package de gestion des logs répondant au standard PSR-3 présenté dans un chapitre précédent[où?] mais moyennant quelques adaptations (essentiellement à partir de la version 2.6) il remplit le contrat non plus à 80 mais à 100%.

9.4.2.Installation

Pour pouvoir utiliser zend-log dans votre projet géré avec composer[c'est quoi?], vous devez ajouter une ligne du type "zendframework/zend-log": "^2.6" dans votre fichier composer.json. Ce qui peut se faire en lançant (depuis le dossier racine de votre projet) la commande > composer require zendframework/zend-log.

9.4.3.Instanciation

La classe à instancier s'appelle Zend\Log\Logger.
<?php
use Zend\Log\Logger;

$logger = new Logger();
Bien que cette classe propose les 8 méthodes (correspondants aux 8 niveaux de criticité) requises par le standard PSR-3 (et avec la même interface), elle n'implémente pas pour autant l'interface Psr\Log\LoggerInterface du standard PSR-3.
De même, si la classe Zend propose bien la 9ème méthode PSR-3 log() avec la même interface, les valeurs associées aux différents niveaux de criticité ne sont pas ceux définies par les constantes PSR-3 (par exemple avec Zend-Log le niveau critique est associé à la valeur 2 définie par la constante Zend\Log\Logger:CRIT tandis que dans le standard PSR-3 il est associé à la valeur 'critical' définie par la constante Psr\Log\LogLevel::CRITICAL).
Si vous souhaitez utiliser un Logger implémentant Psr\Log\LoggerInterface avec une implémentation Zend vous devrez passer par l'"adaptateur" Zend\Log\PsrLoggerAdapter (disponible uniquement depuis la version 2.6).
<?php
use Zend\Log\Logger;
use Zend\Log\PsrLoggerAdapter;

$loggerZend = new Logger();
$logger = new PsrLoggerAdapter($loggerZend);

9.4.4.Ajout des flux de sortie

Pour ajouter un flux de sortie, il faut faire appel à la méthode addWriter() à laquelle on passe un objet implémentant Zend\Log\Writer\WriterInterface (ou une réference à un plugin instanciant un objet implémentant cette interface) parmi lesquels nous trouvons notamment:
  • Zend\Log\Writer\Stream pour stocker le message dans un fichier (ou le renvoyer dans la sortie standard si l'on précise 'php://stdout' comme nom de fichier)
  • Zend\Log\Writer\Noop pour ne pas traiter le message
Pour chacun de ces flux de sortie, il est possible de préciser un filtre afin de préciser quels messages doivent être ignorés. Ceci se fait en faisant appel à la méthode addFilter() du Writer, avec en paramètre un objet implémentant Zend\Log\Filter\FilterInterface parmi lesquels:
  • Zend\Log\Filter\Priority pour rejeter tous les messages de criticité inférieur à un niveau donné
<?php
use Zend\Log\Filter\Priority;
use Zend\Log\Logger;
use Zend\Log\PsrLoggerAdapter;
use Zend\Log\Writer\Stream;

$loggerZend = new Logger();
$logger = new PsrLoggerAdapter($loggerZend);

$writer = new Stream('/tmp/monfichier.log');
$filter = new Priority(Logger::WARN);
$write->addFilter($filter);
$loggerZend->addWriter($writer);
warning La méthode addFilter() est une méthode de l'implémentation Zend de Logger et non pas de l'interface PSR-3

9.4.5.Log

L'utilisation proprement dite, quant à elle, est conforme à ce qui est décrit dans la PSR-3[c'est quoi?] avec des méthodes comme debug(), error(), warning(), etc.
<?php
use Zend\Log\Filter\Priority;
use Zend\Log\Logger;
use Zend\Log\PsrLoggerAdapter;
use Zend\Log\Writer\Stream;

$loggerZend = new Logger();
$logger = new PsrLoggerAdapter($loggerZend);

$writer = new Stream('/tmp/monfichier.log');
$filter = new Priority(Logger::WARN);
$writer->addFilter($filter);
$loggerZend->addWriter($writer);

$logger->debug('Ce message ne sera pas stocké dans le fichier car debug');
$logger->warning('Ce message sera stocké dans le fichier');
$logger->error('Celui-ci aussi');

$logger->error('Quelqu\'un a tout cassé', ['utilisateur' => 'Pierre']);
On aura alors dans le fichier
2018-05-10T20:21:39+02:00 WARN (4): Ce message sera stocké dans le fichier
2018-05-10T20:21:39+02:00 ERR (3): Celui-ci aussi
2018-05-10T20:21:39+02:00 ERR (3): Quelqu'un a tout cassé {"utilisateur":"Pierre"}
Il s'agit là du comportement par défaut mais la chaîne de sortie peut être reformattée. En l'occurrence nous avons la date, le niveau d'alerte, le message et éventuellement le contexte.

9.4.6.Contexte et substitution de mots clés

Nous avons vu que la PSR-3 invite (sans l'imposer) les implémentations à proposer un système de substitution de mots clés dans les messages: Substitution réalisées sur la base d'informations complémentaires passées en second paramètre des méthodes de log. Par défaut, cette substitution n'est pas réalisée par l'implémentation de zend-log. Pour qu'elle soit active, il faut déclarer le "processeur" Zend\Log\Processor\PsrPlaceholder via la méthode addProcessor de Zend\Log\Logger comme suit:
<?php
use Zend\Log\Filter\Priority;
use Zend\Log\Logger;
use Zend\Log\Processor\PsrPlaceholder;
use Zend\Log\PsrLoggerAdapter;
use Zend\Log\Writer\Stream;

$loggerZend = new Logger();
$loggerZend->addProcessor(new PsrPlaceholder());
$logger = new PsrLoggerAdapter($loggerZend);

$writer = new Stream('/tmp/monfichier.log');
$filter = new Priority(Logger::WARN);
$writer->addFilter($filter);
$loggerZend->addWriter($writer);
$logger->error('C\'est {utilisateur} qui a tout cassé', ['utilisateur' => 'Pierre']);
Ce qui pourra donner
2018-05-10T20:21:39+02:00 ERR (3): C'est Pierre qui a tout cassé {"utilisateur":"Pierre"}
On notera que même s'il y a eu substitution, toutes les données du contexte apparaîssent dans le message logué. A noter, le contexte peut contenir plus d'informations que celles effectivement utilisées à des fins de substitution.