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