Logging is hands down the best way to see how your application is behaving, and when utilised properly allows you to catch problems early and make key technical decisions. In PHP specifically, the in-built logging functionality is lacking, however using a library like Monolog gives us all of the functionality we need. Furthermore, the ability to centralise logging to a single location from multiple application servers is very useful, meaning all logs can be viewed in one place. Papertrail is a third party service which can be used for this, and is very simple to set up.

SETTING UP

The first step is to install monolog in your project, this can be done by simply running composer require monolog/monolog - if you are not familiar with composer, please checkout https://getcomposer.org/

The other thing you will need before we begin is a papertrail account app, and the host and port to log to. You can do this by visiting https://papertrailapp.com/ and signing up. Once you are signed up, click add system, and note the host and port displayed at the top of the page for the new system.

BASIC LOGGER

Firstly we will set up a basic example of using monolog with a log file handler to which we can build upon:

<?php

date_default_timezone_set('UTC');

require_once __DIR__ . '/vendor/autoload.php';

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

$logger = new Logger('demo_logger');

// Add log file handler
$logger->pushHandler(new StreamHandler(__DIR__ . '/log/basic.log', Logger::WARNING));

// A couple of test log messages
$logger->addInfo('Something happened and it was fine');
$logger->addWarning('Should not have done that');
$logger->addError('Oh no, its broken');

This example creates a logger called demo_logger and adds a stream handler to it, which writes to a log file log/basic.log, with a minimum log level of warning. Three messages are then logged, only two of which are logged, as the info one is below the minimum level of the handler.

LOGGING PHP ERRORS AND EXCEPTIONS

Next, we will make our logger also log PHP errors and exceptions, as well as user defined messages.

<?php

date_default_timezone_set('UTC');

require_once __DIR__ . '/vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\ErrorHandler;

$logger = new Logger('demo_logger');

// Register the logger to handle PHP errors and exceptions
ErrorHandler::register($logger);

// Add log file handler
$logger->pushHandler(new StreamHandler(__DIR__ . '/log/php_errors.log', Logger::WARNING));

// Throw an exception to test logger
throw new Exception('Oops');

You will notice here that we have added a new line registering the logger as an ErrorHandler. An exception is thrown in this file to test that exceptions are logged as expected.

LOGGING TO PAPERTRAIL

The final step is to integrate Papertrail into our logging setup:

<?php

date_default_timezone_set('UTC');

require_once __DIR__ . '/vendor/autoload.php';

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\SyslogUdpHandler;
use Monolog\ErrorHandler;

$logger = new Logger('demo_logger');

// Register the logger to handle PHP errors and exceptions
ErrorHandler::register($logger);

// Add log file handler
$logger->pushHandler(new StreamHandler(__DIR__ . '/log/php_errors.log', Logger::ERROR));

// Add the papertrail handler
$logger->pushHandler(new SyslogUdpHandler("<host>.papertrailapp.com", XXXXX, LOG_USER, Logger::WARNING));

$logger->addInfo('Something happened and it was fine');
$logger->addWarning('Should not have done that');
$logger->addError('Oh no, its broken');

// Throw an exception to test logger
throw new Exception('Oops');

To do this, a new handler was added to the logger. The new handler is a SyslogUdpHandler, which sends the log message to the given host and port over UDP, with a minimum log level of warning. Here you will need to put the host and port details from your new Papertrail system. When you run this script, you will see two log messages plus an exception in your Papertrail account.

NEXT STEPS

Yep, it's that simple, however there are a number of things we can do to improve our setup. Including injecting our logger into our application classes using a dependency injection container, as well as setting up logrotate on any local log files.

The demos above are all available at https://github.com/gaw508/tutorials/tree/master/monolog-papertrail-tutorial