Backend Development

Logging In PHP Applications With Monolog

Logging In PHP Applications With Monolog

Recording every action in web applications is very important for debugging purposes as well as to be notified if certain problem arises, so in this article we will take a look at how to do this in PHP with the help of Monolog package.

 

 

 

Monolog is a very powerful PHP library used logging purposes. The library is PSR-3 compatible so that it can be type hinted into your applications. Monolog also integrates with the common PHP frameworks like Laravel and Symfony, we will see at the end of this article how to configure and use it in laravel.

 

Installation

$ composer require monolog/monolog

 

To use it by initializing an instance of the Logger class providing the channel name:

require_once 'vendor/autoload.php';
use Monolog\Logger;
$log = new Logger('channel_name');

So what channel name for? In fact monolog works just like events in laravel so every event is related to a specific channel, the same concept applies in Monolog. The logger instance is useless by itself unless you attach it with a handler. The handler tells the logger how to log the messages, in files, or email, or to be saved into DB. There are StreamHandler which is the most common and it logs the messages in files.

Let’s see an example using the StreamHandler:

use Monolog\Handler\StreamHandler;

$log->pushHandler(new StreamHandler(__DIR__'/app.log', Logger::WARNING));

// add records to the log
$log->warning('Foo');
$log->error('Bar');

The StreamHandler constructor accepts the path of the file and Log level, the remaining is to log data by invoking warning(), error() on the $log instance. These methods write the message to the app.log file .There are also other methods like alert(), info(), debug(), notice(), critical() and emergency() which correspond to these log levels:

  • DEBUG

  • INFO

  • NOTICE

  • WARNING

  • ERROR

  • CRITICAL

  • ALERT

  • EMERGENCY

 

Monolog Handlers

Monolog comes with a bunch of builtin handlers from these handlers:

  • StreamHandler: Logs records into any PHP stream, use this for log files.
  • RotatingFileHandler: Logs records to a file and creates one logfile per day.
  • SyslogHandler: Logs records to the syslog.
  • ErrorLogHandler: Logs records to PHP’s error_log() function.
  • NativeMailerHandler: Sends emails using PHP’s mail() function.
  • SwiftMailerHandler: Sends emails using a Swift_Mailer instance.
  • SlackWebhookHandler: Logs records to a Slack account using Slack Webhooks.
  • SlackHandler: Logs records to a Slack account using the Slack API (complex setup).
  • SendGridHandler: Sends emails via the SendGrid API.
  • RedisHandler: Logs records to a redis server.
  • MongoDBHandler: Handler to write records in MongoDB via a Mongo extension connection.
  • ElasticsearchHandler: Logs records to an Elasticsearch server.

There are also handlers for local development testing like:

  • FirePHPHandler: Handler for FirePHP, providing inline console messages within FireBug.
  • ChromePHPHandler: Handler for ChromePHP, providing inline console messages within Chrome.

Refer to this doc here to see the full list of handlers.

 

Let’s update the above example to attach multiple handlers, in that case we will log the messages to the file system and to the mail:

<?php
require_once 'vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\NativeMailerHandler;

$logger = new Logger('app_logger');

$logger->pushHandler(new StreamHandler(__DIR__ . '/app_log.log', Logger::DEBUG));
$logger->pushHandler(new NativeMailerHandler('admin@to_email.com', 'PHP Logger', 'admin@from_email.com'));

$logger->alert("This is an alert message");

 

Creating Custom Handler

To create a custom monolog is so easy by creating a class that implements Monolog\Handler\HandlerInterface. Let’s see this example handler inspired from monolog docs, in this example we created a custom handler to store the logs in mysql database using PDO.

use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;


class PDOHandler extends AbstractProcessingHandler
{
    private $initialized = false;
    private $pdo;
    private $statement;

    public function __construct(PDO $pdo, $level = Logger::DEBUG, bool $bubble = true)
    {
        $this->pdo = $pdo;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record): void
    {
        if (!$this->initialized) {
            $this->initialize();
        }

        $this->statement->execute(array(
            'channel' => $record['channel'],
            'level' => $record['level'],
            'message' => $record['formatted'],
            'time' => $record['datetime']->format('U'),
        ));
    }

    private function initialize()
    {
        $this->pdo->exec(
            'CREATE TABLE IF NOT EXISTS monolog '
            .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
        );
        $this->statement = $this->pdo->prepare(
            'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
        );

        $this->initialized = true;
    }

}

The only you need to implement is the write() method as shown in the above class. This method responsible for writing a log record, in this case i inserted the record into mysql table using the pdo instance. In the constructor a PDO instance is injected so we can create the log table and insert into it.

 

Now to use this handler the same way as the builtin handlers, but first let’s create a new mysql database as shown here:

$logger = new Logger('my_logger');

$logger->pushHandler(new PDOHandler(new PDO("mysql:host=localhost;dbname=monolog_db", "root", "")));

$logger->alert("This is an alert message");

If you run this code it will create the monolog table and insert the log into it.

 

 

Testing Monolog in Development

There are some special handlers that allow you to test monolog in development environment, from these handlers FirePHPHandler, ChromePHPHandler. The most common one is the FirePHPHandler which allow you to test logs in firefox or chrome browsers by sending the logs into the browser console from response headers.

FirePHPHandler Usage

To use FirePHPHandler the first step is to install the FirePHP browser extension:

Next install the firephp/firephp-core composer package:

composer require firephp/firephp-core

Now let’s use the FirePHPHandler:

use Monolog\Logger;
use Monolog\Handler\FirePHPHandler;

$logger = new Logger('my_logger');

$logger->pushHandler(new FirePHPHandler());

$logger->alert("This is an alert message");

Open your browser and enable the FirePHP extension, now you can see the logs as shown in this screenshot

Using Monolog in Laravel

To use monolog in Laravel framework you have to configure the default channel and driver type in config/logging.php as shown:

'default' => env('LOG_CHANNEL', 'stack'),

'channels' => [
'stack' => [
            'driver' => 'monolog',
            'path' => storage_path('logs/laravel.log'),
            'level' => 'debug',
        ]

]

Then to write log messages is a simple matter by using laravel Log facade as follows:

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Log;

class SampleController extends Controller
{
    public function index($message)
    {
        Log::info($message);
        Log::emergency($message);
Log::alert($message);
Log::error($message);
Log::warning($message);
Log::notice($message);
Log::debug($message);

        return view('index');
    }
}

 

 

5 1 vote
Article Rating

What's your reaction?

Excited
1
Happy
0
Not Sure
0
Confused
-2

You may also like

Subscribe
Notify of
guest

1 Comment
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
George The Fag
George The Fag
1 year ago

I ended up here after reading a whole load of generic monolog “tutorials”. This article is better in that it is slightly more advanced and allows me to think about different aspects of the logger I want to achieve. Thanks darling