The Wheel: Monolog
Join the DZone community and get the full member experience.Join For Free
Logging is one of the task that most application have to perform while getting no strategic advantage out of it (and hence not putting an investment into it). There is an alternative to writing a cramped 10-line class for this utility software: introducing a library into your applications that is capable of solving the task quickly.
A quick dive
Monolog decouples two axis of change from the Facade used for logging: Handlers and Formatters. Handlers are the ultimate sink where logged events are sent, while Formatters are used to dump PHP variables to a text format.
$logger = new Logger(__METHOD__); $logger->pushHandler(new StreamHandler(...)); $logger->addError('hey!', array('exception' => $e); $logger->addInfo('not a problem');
Of course creation and usage of the Logger object should be separated in actual code.
The main selling point of Monolog is its flexibility. In addition to the first two axis of change, there is also the possibility of introducing decorators with Processors.
Handlers decide where the logs will be written. The shipped handlers include the classic text, syslog, MongoDB, CouchDB, a socket, the mail() function, even FirePHP for sending logs to the browser.
Moreover, the Handlers namespace contains some utilities: a TestHandler for test suites context, a NullHandler that just throws away the logs, a RotatingFileHandler (not for production purposes but capable of handling rotation where necessary.)
Formatters describe a function for converting any PHP context into a string that can be written on a stream: common formatters include the single line event but also JSON; a normalizer for objects but also for exceptions, including class, message, file and line into the description.
Finally, Processors are essentially Decorators for the logging process, being able to add or remove fields from a log record. As all Decorators, they can be put in a chain. The shipped Processors include facilities to add the memory usage to each event.
As a side note, the WebProcessor takes a copy of $_SERVER in its constructor. I like the hold Dependency Injection has taken in these modern PHP libraries.
The installation of Monolog in your project can be performed via Composer (of course, being the library written by the Composer creator Jordi Boggiano.)
Although composer.json can in theory pull in any any other package, currently is specifies almost no depenedencies, apart from one on... PSR-3, the standard logging interface for PHP.
There have been some debates on this LoggerInterface, but Monolog is promoting as a standard (I personally agree with the direction). Some call it a mistake, but this kind of interface could be even baked into the language (Java has always had its own List and Set interfaces, while PHP...)
In any case, this interface provides you the theoretical opportunity to switch away from Monolog. You would probably need some systems modification as the new log formats may change, dependencing on how standard your formatter was; but you won't need to touch the code.
Note however, that in OOP interfaces are usually dictated by the client. As such, you probably need some Observer or Notifiable interface specific in your application, whose implementation uses Monolog internally. The GOOS link model goes against spreading generic types such as the LoggerInterface into many parts of your application, because it creates a taproot of dependencies going outwards from the key part of it (even to a generic language interface). This discussion is outside of the scope of this post, but just as you wouldn't pass an array or a string representing a domain object to different layers of the application (preferring a Value Object instead), the same is usually true for external dependencies in the form of a service.
Opinions expressed by DZone contributors are their own.