PHP Monolog Tutorial: A Step-by-Step Guide
A developer walks us through how to setup the Monolog logging tool in a PHP-based web application. Read on as we dive in.
Join the DZone community and get the full member experience.
Join For FreeIn application development or maintenance, logging is very important. It gives you the right amount of data that you need to help you monitor your application, logs, databases, code, and web services. Monolog is the existing standard logging library for PHP. It is most popular in PHP frameworks such as Laravel and Symfony, where it implements a common interface for logging libraries.
This article talks about the step-by-step process of using PHP Monolog in your application.
Installation
The basic way to use Monolog in PHP is to install the latest version of the Composer library in your project using this command. You can download it here: https://getcomposer.org/.
Linux
sudo php composer.phar require monolog/monolog
Windows
composer require monolog/monolog
In case you are not using composer, download the PSR-3 source code and install to your application.
Make sure that you are using namespaces (to avoid a headache) so that you don’t require a lot of files.
Create Loggers
First, when you create a logger, the channel name should be included, so that you can distinguish your list of loggers.
$logger = new \Monolog\Logger('channel-name');
$app->container->logger = $logger;
In the example above, ‘channel-name’
should be included in every log entry. This way you can easily look up and filter the entries and/or create another channel for each component. Examples of these channels might include ‘database’, ‘security’, ’business’, and others.
Loggers, by nature, don’t know how to handle logs, but we also have what are called handlers that can handle logs.
require_once(__DIR__.'/vendor/autoload.php');
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
$logger = new Logger('channel-name');
$logger->pushHandler(new StreamHandler(__DIR__.'/app.log', Logger::DEBUG));
$logger->info('This is a log! ^_^ ');
$logger->warning('This is a log warning! ^_^ ');
$logger->error('This is a log error! ^_^ ');
Handlers can be pushed as many times as needed to a Logger instance. These types of handler will decide the kind of logs to be handled. In the example provided above, StreamHandler
reports entries in the file system app.log
.
Intensity Level
An intensity level is added to each log entry, along with channel name to allow you to check and filter the entries.
As illustrated in RFC 5424 which describes the syslog protocol, the following levels of intensity are applied in Monolog.
- DEBUG: Detailed debugging information.
- INFO: Handles normal events. Example: SQL logs.
- NOTICE: Handles normal events, but with more important events.
- WARNING: Warning status, where you should take an action before it will become an error.
- ERROR: Error status, where something is wrong and needs your immediate action.
- CRITICAL: Critical status. Example: System component is not available.
- ALERT: Immediate action should be exercised. This should trigger some alerts and wake you up during night time.
- EMERGENCY: It is used when the system is unusable.
An info log entry of a channel called ‘channel-name,’ for example, looks like this:
[2018-07-05 11:10:35] channel-name.INFO: This is a log entry!
[2018-07-09 02:58:27] channel-name.WARNING: This is a log warning! ^_^ [] []
[2018-07-09 02:58:27] channel-name.ERROR: This is a log error! ^_^ [] []
Monolog stores one add for each type of intensity level, likely, error, notice, warning, info, and so on.
PHP Example Code
The following code is the basic sample setup to log to a file and to fire PHP on the debug level.
DIR.'/vendor/autoload.php');
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologHandlerFirePHPHandler;
$logger = new Logger('logger');
$logger->pushHandler(new StreamHandler(DIR.'/test_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());
$logger->error('Logger is now Ready');
In the sample, there are two handlers in the stack to provide records in two different ways. FirePHPHandler
is described as it is joined on top of the stack. This permits you to tentatively append a logger with bubbling disabled, if you want to revoke other configured loggers.
Handler Order
When you add a log entry handler to the logger instance, it matters which order you push the handler. When a log entry is added, it will directly go to the handler stack. When a handler’s constructor is set to false, it stops traversing through the handler stack.
require_once(DIR.'/vendor/autoload.php');
use MonologLogger;
use MonologHandlerStreamHandler;
use MonologHandlerSwiftMailerHandler;
// Create the Transport
$transporter = new Swift_SmtpTransport('smtp.example.com', 465, 'ssl');
$transporter->setUsername('user@example.com');
$transporter->setPassword('123456');
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transporter);
// Create a message
$message = (new Swift_Message('A CRITICAL log was added'));
$message->setFrom(['example-FROM@example.com' => 'Someone FROM']);
$message->setTo(['someone-TO@example.com' => 'SomeoneTO']);
$logger = new Logger('default');
$logger->pushHandler(new StreamHandler(DIR.'/test.log', Logger::INFO));
$logger->pushHandler(new SwiftMailerHandler($mailer, $message, Logger::CRITICAL, false));
$logger->addCritical('Hey, a critical log entry!');
First, you need to install SwiftMailer (composer require swiftmailer/swiftmailer
) to be able to use the SwiftMailerHandler. As you to be able to send emails, you need to use Swift_SmtpTransport
, Swift_Message
, and Swift_Mailer
to join $mailer
and $message
to the SwiftMailerHandler
instance.
When you examine the last parameter of SwiftMailer’s constructor, it returns false for the last parameter, called the $bubble
parameter. Technically, by default, it returns true, but when set to false it means that it stops traversing the handler stack. This is a technique in which the StreamHandler is located at the bottom of the stack, and thus it never stores logs in the file system if SwiftMailerHandler manages the entry.
Array
Array passing is as simple as the following code:
$username = 'jmendez';
$logger->addInfo('User registered', ['username' => $username]);
This is a way to pass an array to the add
method such as addDebug
, addInfo
, etc.
Processors
In Monolog, you can create your own processor even though it provides a lot of processors by default. Processors are used to include information in log entries such as a client’s IP and browser, and more. Here’s a sample code snippet:
$logger = new Logger('default');
$logger->pushHandler(new StreamHandler(__DIR__.'/test.log', Logger::INFO));
$logger->pushProcessor(function ($entry) {
$entry['extra']['data'] = 'Hello world!';
return $entry;
});
$logger->addInfo('User registered', ['username'=>'jmendez']);
The sample above would simply store the log entry in this format
[2018-07-05 11:18:29] default.INFO: User registered {'username':'jmendez'} {"data":"Hello world!"}
You can also use the built-in processor that Monolog provides. You directly use the class and push an instance using the pushProcessor
method. Here is sample code using pushProcessor
:
use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Processor\WebProcessor;
$logger = new Logger('default');
$logger->pushHandler(new StreamHandler(__DIR__.'/test.log', Logger::INFO));
$logger->pushProcessor(new WebProcessor());
$logger->ddInfo('User registered', ['username'=>'jmendez']);
Formatters
In Monolog, there are a lot of formatters that can be used. You can find some built-in formatters here. You can also customize the format of the logs that are written in files, emails, databases, and other handlers.
$record['formatted']
The code above is the most common way to use a handler with a value to be directly put into the log device. Formatters can be customized, so you can write your own. Here is a simple configuration for a built-in formatter class that formats the log sent by email, which can be understood by everyone who will use your system.
use Monolog\Logger;
use Monolog\Handler\SwiftMailerHandler;
use Monolog\Formatter\HtmlFormatter;
// Create the Transport
$transporter = new Swift_SmtpTransport('smtp.gmail.com', 465, 'ssl');
$transporter->setUsername(user@example.com');
$transporter->setPassword(123456);
// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transporter);
// Create a message
$message = (new Swift_Message('A CRITICAL log was added'));
$message->setFrom(['fromuser@example.com' => 'From User']);
$message->setTo(['touser@example.com' => 'To User']);
$message->setContentType("text/html");
$logger = new Logger('default');
$mailerHandler = new SwiftMailerHandler($mailer, $message, Logger::CRITICAL);
$mailerHandler->setFormatter(new HtmlFormatter());
$logger->pushHandler($mailerHandler);
$logger->addCritical('This is a critical message!');
In the example, I am using an HtmlFormatter
object with SwiftMailer and then defining the $message
and setting content type to text/html. In the email, this would look like this:
Most of the third-party handlers, formatters, and processors can be found in the wiki. You can always write your own if you want!
More Information
See the following articles about PHP logging:
- 18 PHP Tools for Developers of all Levels
- Errors and Logs: Configure PHP Applications
- PHP Logging Best Practices
Summary
Monolog is integrated into most of the popular frameworks like Laravel, Symfony, Slim, and many others. As of today, Monolog is one of the best tools available for logging libraries. I hope this article guides you, and helps you in logging your PHP applications.
Published at DZone with permission of Juliet Mendez. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments