Introduzione
Quando un’applicazione PHP cresce, diventa fondamentale capire che cosa accade durante l’esecuzione: quali richieste sono state ricevute, quali errori si sono verificati, quanto tempo ha impiegato un’operazione e quali dati erano disponibili in quel momento. Il logging, cioè la registrazione degli eventi dell’applicazione, permette di raccogliere queste informazioni in modo ordinato.
Un errore comune consiste nello scrivere direttamente messaggi con echo, var_dump() o funzioni personalizzate sparse nel codice. Questa soluzione può funzionare durante lo sviluppo, ma diventa difficile da mantenere in produzione. È preferibile utilizzare un’interfaccia comune che permetta di cambiare il sistema di registrazione senza modificare ogni classe.
Lo standard PSR-3, definito da PHP-FIG, descrive un’interfaccia comune per i logger PHP. Grazie a PSR-3, una classe può dipendere da un’astrazione, come PsrLogLoggerInterface, invece di conoscere i dettagli del logger concreto. In questo modo è possibile usare un logger che scrive su file, database, console o servizi esterni.
PSR-3 definisce otto livelli di log: emergency, alert, critical, error, warning, notice, info e debug. Ogni livello comunica la gravità dell’evento e aiuta a filtrare i messaggi più importanti.
Codice completo
Il seguente esempio mostra un servizio PHP che registra l’accesso a un account utilizzando PSR-3. Il logger viene ricevuto tramite il costruttore, secondo il principio della dependency injection.
<?php
declare(strict_types=1);
namespace AppSecurity;
use PsrLogLoggerInterface;
final class LoginService
{
public function __construct(
private LoggerInterface $logger
) {
}
public function authenticate(string $email, string $password): bool
{
// Non registriamo mai la password nei log.
$context = [
´email´ => $email,
´ip´ => $_SERVER[´REMOTE_ADDR´] ?? ´unknown´,
];
$this->logger->info(
´Tentativo di autenticazione ricevuto.´,
$context
);
if ($email !== ´[email protected]´ || $password !== ´password-demo´) {
$this->logger->warning(
´Autenticazione fallita.´,
$context
);
return false;
}
$this->logger->notice(
´Autenticazione completata con successo.´,
[´email´ => $email]
);
return true;
}
} Per installare l’interfaccia PSR-3 in un progetto Composer si può utilizzare il pacchetto ufficiale di PHP-FIG:
composer require psr/log Durante lo sviluppo è possibile utilizzare un logger concreto come Monolog, molto diffuso nell’ecosistema PHP:
composer require monolog/monolog Un esempio di configurazione dell’applicazione potrebbe essere il seguente:
<?php
declare(strict_types=1);
use AppSecurityLoginService;
use MonologHandlerStreamHandler;
use MonologLevel;
use MonologLogger;
require dirname(__DIR__) . ´/vendor/autoload.php´;
$logger = new Logger(´application´);
// I messaggi vengono aggiunti al file storage/logs/app.log.
$logger->pushHandler(
new StreamHandler(
dirname(__DIR__) . ´/storage/logs/app.log´,
Level::Info
)
);
$loginService = new LoginService($logger);
$isAuthenticated = $loginService->authenticate(
´[email protected]´,
´password-demo´
);
echo $isAuthenticated
? ´Login eseguito´
: ´Credenziali non valide´; Spiegazione
L’interfaccia LoggerInterface
La classe LoginService non dipende direttamente da Monolog. Utilizza invece LoggerInterface, che appartiene al pacchetto psr/log. Questa scelta riduce l’accoppiamento e rende il codice più facilmente testabile.
Qualunque logger compatibile con PSR-3 può essere passato al servizio. In futuro si potrebbe sostituire Monolog con un altro componente senza riscrivere il metodo authenticate().
I livelli di log
- emergency: il sistema è inutilizzabile, ad esempio un’intera applicazione non disponibile.
- alert: è necessario intervenire immediatamente.
- critical: si è verificato un problema molto grave.
- error: un’operazione non è stata completata correttamente.
- warning: si è verificata una situazione anomala, ma l’applicazione può continuare.
- notice: evento significativo che non rappresenta un errore.
- info: informazione utile sul normale funzionamento.
- debug: dettaglio tecnico destinato principalmente allo sviluppo.
La scelta del livello deve essere coerente. Un tentativo di login con password errata può essere un warning, mentre un database irraggiungibile potrebbe essere un critical o un error, in base alle conseguenze.
Il parametro context
Il secondo parametro dei metodi PSR-3 è un array associativo chiamato context. Serve ad aggiungere dati strutturati al messaggio: identificativo dell’utente, indirizzo IP, ordine coinvolto o codice dell’errore.
È preferibile usare il contesto invece di concatenare manualmente tutte le informazioni nella stringa. Un logger concreto può infatti formattare questi dati in modo leggibile o inviarli a un sistema di analisi centralizzato.
Registrare le eccezioni
PSR-3 prevede una convenzione importante: quando il contesto contiene un’eccezione, questa dovrebbe essere inserita nella chiave exception. In questo modo il logger può registrare correttamente messaggio, classe e stack trace.
try {
$paymentService->charge($amount);
} catch (Throwable $exception) {
$logger->error(
´Errore durante il pagamento.´,
[
´order_id´ => $orderId,
´exception´ => $exception,
]
);
throw $exception;
} Best practice
- Non registrare dati sensibili: password, token, numeri completi di carte e chiavi private non devono finire nei log.
- Usare messaggi chiari: un messaggio come “Errore generico” offre poche informazioni. Indicare l’operazione coinvolta, senza esporre dati riservati.
- Preferire il contesto strutturato: inserire identificativi e metadati nell’array
context. - Iniettare il logger: evitare di creare direttamente un logger dentro ogni classe. La dependency injection semplifica test e sostituzioni.
- Configurare livelli diversi: in sviluppo si possono abilitare messaggi
debug, mentre in produzione è spesso opportuno filtrare i livelli meno importanti. - Proteggere i file di log: la directory dei log non dovrebbe essere accessibile direttamente dal web server.
- Usare rotazione e conservazione: i log devono essere ruotati periodicamente per evitare file enormi e per rispettare eventuali requisiti di conservazione.
- Mantenere uno stile PSR-12: dichiarazioni, namespace, import e metodi devono seguire una formattazione coerente.
Riepilogo
PSR-3 fornisce un contratto standard per il logging in PHP. Il vantaggio principale è separare il codice applicativo dal sistema concreto che salva i messaggi. Una classe deve dipendere da LoggerInterface, ricevere il logger tramite il costruttore e usare correttamente livelli e contesto.
Questo approccio rende il progetto più flessibile, testabile e manutenibile. Monolog può essere utilizzato come implementazione concreta, ma il servizio applicativo rimane compatibile con qualunque logger conforme a PSR-3. Applicando inoltre le regole di PSR-12 e proteggendo i dati sensibili, si ottiene una soluzione adatta anche a progetti PHP professionali.
Approfondisci con risorse ufficiali
- PSR-3 – Logger Interface: specifica ufficiale dello standard di logging di PHP-FIG.
- PSR-12 – Extended Coding Style: regole ufficiali per la formattazione del codice PHP.
- PHP-FIG: sito ufficiale del PHP Framework Interop Group, che pubblica le specifiche PSR.
- Documentazione di Monolog: guida all’uso di handler, formatter, canali e livelli di log.
- Documentazione di Composer: riferimento per installare e gestire i pacchetti
psr/logemonolog/monolog.
