janos.szurovecz.hu

A régi blogom, ahova lehet írok majd még...

Loggolás másként - lf4php

2013-01-18 3 perc olvasási idő

Java fejlesztőként találkoztam az slf4j-vel, ami nem más, mint egy logging facade. Önmagában nem sok mindenre jó: mint ahogy a neve is sejteti, elrejti előlünk a konkrét megvalósítást, absztrakt felületet ad. Használatával bármikor válthatunk egyik logging keretrendszerről a másikra. Innen vettem az ötletet, és nem titkoltan az slf4j forráskódját bújva készítettem el az lf4php-t. Egy korábbi írásomban már megemlítettem, most bemutatom, hogyan kell használni, illetve milyen irányelvek vezettek a tervezése és fejlesztése során.

Használat

Az osztályainkban mindössze el kell kérni egy loggert a LoggerFactory-tól és már mehet is a móka. Például:

$logger = LoggerFactory::getLogger(__CLASS__);  
$logger->debug("Hello");  

Jaj, mi ez a statikusság, miért nem DI?!

Jómagam nagy híve vagyok a DI-nak, illetve a DIC használatának. Miért nem adom át akkor (injektálom) a logger objektumokat az osztálynak? Ennek több oka is van:

  • A DIC konfigurációs fájlomat nem kell megtömni logger függőségekkel.
  • Az osztályaimat nem kell setLogger() metódushívással díszítenem, illetve valamiféle LoggerAware interfészt implementálnom.
  • Ha a loggolási szintet finomhangolni akarom, elég csak a megfelelő namespace nevével regisztrálnom egy loggert és onnantól az lesz érvényben minden az alatt található osztályra nézve.
  • Véleményem szerint a loggolásnak mindenhonnan könnyen elérhetőnek kell lennie, mivel ez egy elemi funkció.

Namespace szerinti konfigurálás

Tegyük fel, van egy lib, ami lf4php-t használ. Tele van szórva különböző szintű logokkal. Mi is lf4php-t használunk a saját kódunkban. Fejlesztés közben viszont nem szeretnénk minden debug üzenetet látni, elég csak az, ami a mi kódunkból jön. Az is elképzelhető, hogy még finomabb beállításokat szeretnénk: hibajavítás során csak abból az osztályból jövő trace logokat szeretnénk látni (és nem akarunk elveszni a log tengerben), amin épp dolgozunk.

Mindez elérhető úgy, hogy a finomhangolni kívánt namespace, vagy osztály nevével beregisztrálunk egy megfelelően konfigurált loggert. A log4php natívan támogatja ezt, nézzük meg, Monolog esetén hogy járhatunk el.

$monologFactory = new MonologLoggerFactory();
$monolog = new \Monolog\Logger('foo\bar');
// itt konfiguráljuk a Monolog loggert a Monolog dokumentációja alapján
$monologFactory->registerMonologLogger($monolog);
LoggerFactory::setILoggerFactory($monologFactory);

Ha a foo\bar egy namespace és van pl. egy foo\bar\Service osztályunk, akkor az abból jövő összes log esemény a fenti $monolog loggernek kerül átadásra. Egészen addig, amíg be nem regisztrálunk egy másik loggert mondjuk a foo\bar\Service névvel. Tehát az lf4php megkeresi a hierarchia szerinti legközelebbi regisztrált loggert. Ezért érdemes mindig a __CLASS__ névvel elkérni a példányt.

Paraméteres log üzenetek

Az slf4j-hez hasonló módon az lf4php is támogatja a paramétereket. Az üzenetbe tetszőleges számú {} párt tehetünk, amelyek lecserélődnek a paraméterben átadott tömb megfelelő elemeivel.

$logger->debug('Hello {}, derűs {}!', array('Jani', 'estét'));

Kivételeket harmadik, opcionális paraméterként adhatunk át.

$logger->error('Jaj, mi történt!', null, $exception);

Oké, de hogy használom mondjuk a log4php-vel?

Az lf4php egy interfészt ad, valamint néhány alapvető segéd metódust, amit aztán a binderek implementálnak, illetve felhasználhatnak. Ahhoz, hogy a log4php-t használjuk, szükségünk lesz az lf4hp-logf4php csomagra. Ez köti össze a két libet. A konfigurációhoz mindösszesen a következőre van szükség.

Logger::configure('config.xml');
LoggerFactory::setILoggerFactory(new Log4phpLoggerFactory());

A binderek nyilvánvalóan függenek az lf4php-től. Ha log4php helyett mondjuk monolog-ot szeretnénk használni, dobjuk ki a meglévő bindert és használjuk a monolog bindert. Az alkalmazásunkban kizárólag a konfigurációt kell megváltoztatni.

És a PSR-3?

Igen, időközben megalkották a PSR-3-mat, ami alapvetően pozitívum, csak épp a megvalósítással (mármint az interfész kapcsán) van néhány problémám. Mindazonáltal úgy gondolom, hogy az lf4php-nek van létjogosultsága. Egyrészt az interfész véleményem szerint tisztább (gondolok itt a paraméterekre, valamint az ‘exception’ kulcsra). Ráadásul a két megoldás megfér egymás mellett is. Ha egy framework PSR-3 loggerre dependál és mi mondjuk lf4php-t használnánk, akkor felkonfiguráljuk a monologot és hagyjuk, hogy a libek a preferált interfészen keresztül használják azt. Egyébként tervezem, hogy készítek egy PSR-3 bindert, amivel aztán bármilyen “standard” logging keretrendszert felhasználhatunk lf4php-n keresztül.

comments powered by Disqus