You should really be

using monolog

Cascade-Guest: "Cascade WiFi 2008."

monolog

Software Developer at Cascade Energy, Inc.

 Will Vaughn

@nackjicholsonn

github:nackjicholson

willieviseoae@gmail.com

will.vaughn@cascadeenergy.com

Symfony2, Silex, AngularJs

Amazon Web Services, NodeJS

monolog

You should really just be using monolog

 Monolog

monolog

 Monolog

  • Delivers logs
  • Configurable
  • Extensible

monolog

 Monolog

  • Searchability
  • Monitoring
  • Reporting

monolog

 Install


"require": {
    "monolog/monolog": "1.x"
}

composer.json


$ composer require "monolog/monolog"="1.x"

composer cli

monolog

       debug

            info

         notice

      warning

           error

        critical

           alert

emergency

 PSR-3

Detailed debug information

Interesting events

Normal but significant events

Exceptional occurrences, not errors

Expected runtime errors

Critical conditions, in need of action

Immediate action is necessary

Catastrophic failure, system unusable

monolog

100 -- Logger::DEBUG

200 -- Logger::INFO

250 -- Logger::NOTICE

300 -- Logger::WARNING

400 -- Logger::ERROR

500 -- Logger::CRITICAL

550 -- Logger::ALERT

600 -- Logger::EMERGENCY

 PSR-3

Monolog levels:

monolog

 Simple logs

<?php

use Monolog\Logger;

require 'vendor/autoload.php';

$logger = new Logger('channel');

$logger->debug('debug test');
$logger->warning('warning test');

[2014-11-01 21:46:40] channel.DEBUG: debug test [] []
[2014-11-01 21:46:40] channel.WARNING: warning test [] []

monolog

Monolog provides A TON of built in Handlers.

 Handlers

  • StreamHandler
  • RotatingFileHandler
  • NativeMailerHandler
  • PushoverHandler
  • NewRelicHandler
  • LogglyHandler
  • GelfHandler (Graylog2)
  • ZendMonitorHandler
  • ChromePHPHandler
  • SwiftMailerHandler
  • RavenHandler (Sentry)
  • MongoDBHandler
  • DynamoDBHandler
  • ElasticSearchHandler
  • RedisHandler
  • HipChatHandler

and many more...

monolog

Log to multiple destinations.

 Handlers


$filePath = __DIR__ . '/multiple.streams.log';

// Default takes everything >= Logger::DEBUG
$stdoutHandler = new StreamHandler('php://stdout');

// File only handles records with Level >= Logger::WARNING
$fileHandler = new StreamHandler($filePath, Logger::WARNING);

$logger = new Logger('channel');
$logger->pushHandler($stdoutHandler);
$logger->pushHandler($fileHandler);

$logger->info('stdout only');
$logger->warning('stdout and file');
$logger->debug('stdout only');
$logger->error('stdout and file');

# Logged to file

[2014-11-02 01:26:37] channel.WARNING: stdout and file [] []
[2014-11-02 01:26:37] channel.ERROR: stdout and file []


# Logged to stdout

[2014-11-02 01:26:37] channel.INFO: stdout only [] []
[2014-11-02 01:26:37] channel.WARNING: stdout and file [] []
[2014-11-02 01:26:37] channel.DEBUG: stdout only [] []
[2014-11-02 01:26:37] channel.ERROR: stdout and file []

monolog

Don't bother me unless theres a real problem.

 Handlers


$handler = new StreamHandler('php://stdout');
$fingersCrossed = new FingersCrossedHandler($handler, Logger::CRITICAL);

$logger = new Logger("channel");
$logger->pushHandler($fingersCrossed);

// These aren't handled until a log of level >= Logger::CRITICAL
$logger->info('info msg');
$logger->notice('notice msg');

// All sent with this one
$logger->critical('critical msg');

# Logged to stdout as a batch

[2014-11-02 01:26:37] channel.INFO: info msg [] []
[2014-11-02 01:26:37] channel.NOTICE: notice msg [] []
[2014-11-02 01:26:37] channel.CRITICAL: critical msg [] []

monolog

Send it all at the end with BufferHandler.

 Handlers


// Default to only handling levels >= Logger::CRITICAL
$gitterHandler = new GitterImHandler('apitoken', 'roomId');
$bufferHandler = new BufferHandler($gitterHandler);

$logger = new Logger("channel");
$logger->pushHandler($bufferHandler);

// Buffered, and handled as batch at the end.
$logger->debug('test.debug ignored.');
$logger->critical('test.critical in gitter.im');
$logger->notice('test.notice');
$logger->emergency('test.emergency in gitter.im');
$logger->error('test.error');

Trait for classes which have Logger as a dependency.

 Injection


trait LoggerAwareTrait
{
    /** @var LoggerInterface */
    protected $logger;

    /**
     * Sets a logger.
     * 
     * @param LoggerInterface $logger
     */
    public function setLogger(LoggerInterface $logger)
    {
        $this->logger = $logger;
    }
}

monolog

 Records


$record = array(
    'message' => string,
    'context' => array
    'level' => integer,
    'level_name' => string,
    'channel' => string,
    'datetime' => float (unix microtime)
    'extra' => array
);

The data currency of monolog.

monolog

"channel-environment-system"

 Channels

// Too generic.
$logger = new Logger('foobar');
$logger = new Logger('myWebsite');

// Awesomely specific.
$logger = new Logger('cascade-staging-www');
$logger = new Logger('cascade-production-www');
$logger = new Logger('cascade-development-weather');
$logger = new Logger('otherCompany-development-weather');

monolog

 Context


$logger->debug('my message', ['foo' => 'bar']);

monolog

 Context


[2014-11-02 01:26:37] channel.DEBUG: my message {"foo":"bar"} []

monolog

 Context

    
$user = new User("will");
$db->put($user);
$logger->info('User ' . $user->username . ' saved.');

monolog

 Context


[2014-11-02 01:26:37] channel.INFO: User will saved. [] []

monolog

 Context


$user = new User("will");
$db->put($user);

$context = get_object_vars($user);
$logger->info("User saved.", $context);

monolog

 Context


[2014-11-02 01:26:37] channel.INFO: User saved. {"username":"will"} []

monolog

 Formatters

  JsonFormatter


public function format(array $record)
{
    return json_encode($record) . ($this->appendNewline ? "\n" : '');
}

monolog

 Processors

  • MemoryUsageProcessor 
  • ProcessIdProcessor
  • IntrospectionProcessor
  • WebProcessor

monolog

 Processors

class MemoryUsageProcessor extends MemoryProcessor
{
    public function __invoke(array $record)
    {
        $bytes = memory_get_usage($this->realUsage);
        $formatted = $this->formatBytes($bytes);

        $record['extra'] = array_merge(
            $record['extra'],
            array(
                'memory_usage' => $formatted,
            )
        );

        return $record;
    }
}

You should really be using monolog

By Will Vaughn

You should really be using monolog

  • 1,638