Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

PHP Monolog Tutorial: A Step-by-Step Guide

DZone's Guide to

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.

· Web Dev Zone ·
Free Resource

Bugsnag monitors application stability, so you can make data-driven decisions on whether you should be building new features, or fixing bugs. Learn more.

In 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!');

Image title

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_SmtpTransportSwift_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 addDebugaddInfo, 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:

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.

Monitor application stability with Bugsnag to decide if your engineering team should be building new features on your roadmap or fixing bugs to stabilize your application.Try it free.

Topics:
php ,web dev ,logging ,monolog ,tutorial

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}