1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-08-05 20:57:36 +02:00

Merge branch '1.x' into rgb/signal-handler

This commit is contained in:
Robert Gust-Bardon
2018-06-18 08:18:18 -05:00
52 changed files with 695 additions and 201 deletions

View File

@@ -9,7 +9,7 @@ php:
- 5.6 - 5.6
- 7.0 - 7.0
- 7.1 - 7.1
- hhvm - 7.2
- nightly - nightly
matrix: matrix:

View File

@@ -2,7 +2,6 @@
[![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) [![Total Downloads](https://img.shields.io/packagist/dt/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
[![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog) [![Latest Stable Version](https://img.shields.io/packagist/v/monolog/monolog.svg)](https://packagist.org/packages/monolog/monolog)
[![Reference Status](https://www.versioneye.com/php/monolog:monolog/reference_badge.svg)](https://www.versioneye.com/php/monolog:monolog/references)
Monolog sends your logs to files, sockets, inboxes, databases and various Monolog sends your logs to files, sockets, inboxes, databases and various

View File

@@ -55,6 +55,7 @@
- _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account. - _RollbarHandler_: Logs records to a [Rollbar](https://rollbar.com/) account.
- _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server. - _SyslogUdpHandler_: Logs records to a remote [Syslogd](http://www.rsyslog.com/) server.
- _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account. - _LogEntriesHandler_: Logs records to a [LogEntries](http://logentries.com/) account.
- _InsightOpsHandler_: Logs records to a [InsightOps](https://www.rapid7.com/products/insightops/) account.
### Logging in development ### Logging in development

View File

@@ -39,6 +39,7 @@ class ErrorHandler
private $hasFatalErrorHandler; private $hasFatalErrorHandler;
private $fatalLevel; private $fatalLevel;
private $reservedMemory; private $reservedMemory;
private $lastFatalTrace;
private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR); private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
private $previousSignalHandler = array(); private $previousSignalHandler = array();
@@ -192,6 +193,13 @@ class ErrorHandler
if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) { if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
$level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL; $level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
$this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line)); $this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
} else {
// http://php.net/manual/en/function.debug-backtrace.php
// As of 5.3.6, DEBUG_BACKTRACE_IGNORE_ARGS option was added.
// Any version less than 5.3.6 must use the DEBUG_BACKTRACE_IGNORE_ARGS constant value '2'.
$trace = debug_backtrace((PHP_VERSION_ID < 50306) ? 2 : DEBUG_BACKTRACE_IGNORE_ARGS);
array_shift($trace); // Exclude handleError from trace
$this->lastFatalTrace = $trace;
} }
if ($this->previousErrorHandler === true) { if ($this->previousErrorHandler === true) {
@@ -213,7 +221,7 @@ class ErrorHandler
$this->logger->log( $this->logger->log(
$this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel, $this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'], 'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line']) array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'], 'trace' => $this->lastFatalTrace)
); );
if ($this->logger instanceof Logger) { if ($this->logger instanceof Logger) {

View File

@@ -62,6 +62,7 @@ class FluentdFormatter implements FormatterInterface
$message = array( $message = array(
'message' => $record['message'], 'message' => $record['message'],
'context' => $record['context'],
'extra' => $record['extra'], 'extra' => $record['extra'],
); );

View File

@@ -58,7 +58,7 @@ class HtmlFormatter extends NormalizerFormatter
$td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>'; $td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>';
} }
return "<tr style=\"padding: 4px;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$td."</td>\n</tr>"; return "<tr style=\"padding: 4px;text-align: left;\">\n<th style=\"vertical-align: top;background: #ccc;color: #000\" width=\"100\">$th:</th>\n<td style=\"padding: 4px;text-align: left;vertical-align: top;background: #eee;color: #000\">".$td."</td>\n</tr>";
} }
/** /**

View File

@@ -138,18 +138,23 @@ class JsonFormatter extends NormalizerFormatter
* *
* @return mixed * @return mixed
*/ */
protected function normalize($data) protected function normalize($data, $depth = 0)
{ {
if ($depth > 9) {
return 'Over 9 levels deep, aborting normalization';
}
if (is_array($data) || $data instanceof \Traversable) { if (is_array($data) || $data instanceof \Traversable) {
$normalized = array(); $normalized = array();
$count = 1; $count = 1;
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
if ($count++ >= 1000) { if ($count++ > 1000) {
$normalized['...'] = 'Over 1000 items, aborting normalization'; $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
break; break;
} }
$normalized[$key] = $this->normalize($value);
$normalized[$key] = $this->normalize($value, $depth+1);
} }
return $normalized; return $normalized;

View File

@@ -55,8 +55,12 @@ class NormalizerFormatter implements FormatterInterface
return $records; return $records;
} }
protected function normalize($data) protected function normalize($data, $depth = 0)
{ {
if ($depth > 9) {
return 'Over 9 levels deep, aborting normalization';
}
if (null === $data || is_scalar($data)) { if (null === $data || is_scalar($data)) {
if (is_float($data)) { if (is_float($data)) {
if (is_infinite($data)) { if (is_infinite($data)) {
@@ -75,11 +79,12 @@ class NormalizerFormatter implements FormatterInterface
$count = 1; $count = 1;
foreach ($data as $key => $value) { foreach ($data as $key => $value) {
if ($count++ >= 1000) { if ($count++ > 1000) {
$normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization'; $normalized['...'] = 'Over 1000 items ('.count($data).' total), aborting normalization';
break; break;
} }
$normalized[$key] = $this->normalize($value);
$normalized[$key] = $this->normalize($value, $depth+1);
} }
return $normalized; return $normalized;

View File

@@ -102,12 +102,12 @@ class WildfireFormatter extends NormalizerFormatter
throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter'); throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter');
} }
protected function normalize($data) protected function normalize($data, $depth = 0)
{ {
if (is_object($data) && !$data instanceof \DateTime) { if (is_object($data) && !$data instanceof \DateTime) {
return $data; return $data;
} }
return parent::normalize($data); return parent::normalize($data, $depth);
} }
} }

View File

@@ -33,7 +33,7 @@ abstract class AbstractHandler implements HandlerInterface
/** /**
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($level = Logger::DEBUG, $bubble = true) public function __construct($level = Logger::DEBUG, $bubble = true)
{ {
@@ -141,7 +141,7 @@ abstract class AbstractHandler implements HandlerInterface
/** /**
* Sets the bubbling behavior. * Sets the bubbling behavior.
* *
* @param Boolean $bubble true means that this handler allows bubbling. * @param bool $bubble true means that this handler allows bubbling.
* false means that bubbling is not permitted. * false means that bubbling is not permitted.
* @return self * @return self
*/ */
@@ -155,7 +155,7 @@ abstract class AbstractHandler implements HandlerInterface
/** /**
* Gets the bubbling behavior. * Gets the bubbling behavior.
* *
* @return Boolean true means that this handler allows bubbling. * @return bool true means that this handler allows bubbling.
* false means that bubbling is not permitted. * false means that bubbling is not permitted.
*/ */
public function getBubble() public function getBubble()

View File

@@ -55,7 +55,7 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler
/** /**
* @param mixed $facility * @param mixed $facility
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true) public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
{ {

View File

@@ -43,11 +43,11 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
protected function write(array $record) protected function write(array $record)
{ {
// Accumulate records // Accumulate records
self::$records[] = $record; static::$records[] = $record;
// Register shutdown handler if not already done // Register shutdown handler if not already done
if (!self::$initialized) { if (!static::$initialized) {
self::$initialized = true; static::$initialized = true;
$this->registerShutdownFunction(); $this->registerShutdownFunction();
} }
} }
@@ -58,18 +58,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
*/ */
public static function send() public static function send()
{ {
$format = self::getResponseFormat(); $format = static::getResponseFormat();
if ($format === 'unknown') { if ($format === 'unknown') {
return; return;
} }
if (count(self::$records)) { if (count(static::$records)) {
if ($format === 'html') { if ($format === 'html') {
self::writeOutput('<script>' . self::generateScript() . '</script>'); static::writeOutput('<script>' . static::generateScript() . '</script>');
} elseif ($format === 'js') { } elseif ($format === 'js') {
self::writeOutput(self::generateScript()); static::writeOutput(static::generateScript());
} }
self::reset(); static::reset();
} }
} }
@@ -78,7 +78,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
*/ */
public static function reset() public static function reset()
{ {
self::$records = array(); static::$records = array();
} }
/** /**
@@ -133,18 +133,18 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
private static function generateScript() private static function generateScript()
{ {
$script = array(); $script = array();
foreach (self::$records as $record) { foreach (static::$records as $record) {
$context = self::dump('Context', $record['context']); $context = static::dump('Context', $record['context']);
$extra = self::dump('Extra', $record['extra']); $extra = static::dump('Extra', $record['extra']);
if (empty($context) && empty($extra)) { if (empty($context) && empty($extra)) {
$script[] = self::call_array('log', self::handleStyles($record['formatted'])); $script[] = static::call_array('log', static::handleStyles($record['formatted']));
} else { } else {
$script = array_merge($script, $script = array_merge($script,
array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))), array(static::call_array('groupCollapsed', static::handleStyles($record['formatted']))),
$context, $context,
$extra, $extra,
array(self::call('groupEnd')) array(static::call('groupEnd'))
); );
} }
} }
@@ -154,19 +154,19 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
private static function handleStyles($formatted) private static function handleStyles($formatted)
{ {
$args = array(self::quote('font-weight: normal')); $args = array(static::quote('font-weight: normal'));
$format = '%c' . $formatted; $format = '%c' . $formatted;
preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER); preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
foreach (array_reverse($matches) as $match) { foreach (array_reverse($matches) as $match) {
$args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0])); $args[] = static::quote(static::handleCustomStyles($match[2][0], $match[1][0]));
$args[] = '"font-weight: normal"'; $args[] = '"font-weight: normal"';
$pos = $match[0][1]; $pos = $match[0][1];
$format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0])); $format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
} }
array_unshift($args, self::quote($format)); array_unshift($args, static::quote($format));
return $args; return $args;
} }
@@ -198,13 +198,13 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
if (empty($dict)) { if (empty($dict)) {
return $script; return $script;
} }
$script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title)); $script[] = static::call('log', static::quote('%c%s'), static::quote('font-weight: bold'), static::quote($title));
foreach ($dict as $key => $value) { foreach ($dict as $key => $value) {
$value = json_encode($value); $value = json_encode($value);
if (empty($value)) { if (empty($value)) {
$value = self::quote(''); $value = static::quote('');
} }
$script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value); $script[] = static::call('log', static::quote('%s: %o'), static::quote($key), $value);
} }
return $script; return $script;
@@ -220,7 +220,7 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
$args = func_get_args(); $args = func_get_args();
$method = array_shift($args); $method = array_shift($args);
return self::call_array($method, $args); return static::call_array($method, $args);
} }
private static function call_array($method, array $args) private static function call_array($method, array $args)

View File

@@ -34,8 +34,8 @@ class BufferHandler extends AbstractHandler
* @param HandlerInterface $handler Handler. * @param HandlerInterface $handler Handler.
* @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param int $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded * @param bool $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
*/ */
public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false) public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
{ {

View File

@@ -45,7 +45,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
* *
* Chrome limits the headers to 256KB, so when we sent 240KB we stop sending * Chrome limits the headers to 256KB, so when we sent 240KB we stop sending
* *
* @var Boolean * @var bool
*/ */
protected static $overflowed = false; protected static $overflowed = false;
@@ -59,7 +59,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
/** /**
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($level = Logger::DEBUG, $bubble = true) public function __construct($level = Logger::DEBUG, $bubble = true)
{ {
@@ -174,7 +174,7 @@ class ChromePHPHandler extends AbstractProcessingHandler
/** /**
* Verifies if the headers are accepted by the current user agent * Verifies if the headers are accepted by the current user agent
* *
* @return Boolean * @return bool
*/ */
protected function headersAccepted() protected function headersAccepted()
{ {

View File

@@ -60,7 +60,7 @@ class DeduplicationHandler extends BufferHandler
* @param string $deduplicationStore The file/path where the deduplication log should be kept * @param string $deduplicationStore The file/path where the deduplication log should be kept
* @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes * @param int $deduplicationLevel The minimum logging level for log records to be looked at for deduplication purposes
* @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through * @param int $time The period (in seconds) during which duplicate entries should be suppressed after a given log is sent through
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true) public function __construct(HandlerInterface $handler, $deduplicationStore = null, $deduplicationLevel = Logger::ERROR, $time = 60, $bubble = true)
{ {

View File

@@ -49,7 +49,7 @@ class ElasticSearchHandler extends AbstractProcessingHandler
* @param Client $client Elastica Client object * @param Client $client Elastica Client object
* @param array $options Handler configuration * @param array $options Handler configuration
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true) public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
{ {

View File

@@ -30,8 +30,8 @@ class ErrorLogHandler extends AbstractProcessingHandler
/** /**
* @param int $messageType Says where the error should go. * @param int $messageType Says where the error should go.
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries * @param bool $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
*/ */
public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false) public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false)
{ {

View File

@@ -40,7 +40,7 @@ class FilterHandler extends AbstractHandler
/** /**
* Whether the messages that are handled can bubble up the stack or not * Whether the messages that are handled can bubble up the stack or not
* *
* @var Boolean * @var bool
*/ */
protected $bubble; protected $bubble;
@@ -48,7 +48,7 @@ class FilterHandler extends AbstractHandler
* @param callable|HandlerInterface $handler Handler or factory callable($record, $this). * @param callable|HandlerInterface $handler Handler or factory callable($record, $this).
* @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided * @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
* @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array * @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true) public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
{ {

View File

@@ -22,7 +22,7 @@ interface ActivationStrategyInterface
* Returns whether the given record activates the handler. * Returns whether the given record activates the handler.
* *
* @param array $record * @param array $record
* @return Boolean * @return bool
*/ */
public function isHandlerActivated(array $record); public function isHandlerActivated(array $record);
} }

View File

@@ -41,8 +41,8 @@ class FingersCrossedHandler extends AbstractHandler
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler). * @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
* @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action * @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
* @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer. * @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true) * @param bool $stopBuffering Whether the handler should stop buffering after being triggered (default true)
* @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered * @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
*/ */
public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null) public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)

View File

@@ -158,7 +158,7 @@ class FirePHPHandler extends AbstractProcessingHandler
/** /**
* Verifies if the headers are accepted by the current user agent * Verifies if the headers are accepted by the current user agent
* *
* @return Boolean * @return bool
*/ */
protected function headersAccepted() protected function headersAccepted()
{ {

View File

@@ -47,14 +47,6 @@ class GelfHandler extends AbstractProcessingHandler
$this->publisher = $publisher; $this->publisher = $publisher;
} }
/**
* {@inheritdoc}
*/
public function close()
{
$this->publisher = null;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
*/ */

View File

@@ -24,7 +24,7 @@ class GroupHandler extends AbstractHandler
/** /**
* @param array $handlers Array of Handlers. * @param array $handlers Array of Handlers.
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(array $handlers, $bubble = true) public function __construct(array $handlers, $bubble = true)
{ {

View File

@@ -31,7 +31,7 @@ interface HandlerInterface
* *
* @param array $record Partial log record containing only a level key * @param array $record Partial log record containing only a level key
* *
* @return Boolean * @return bool
*/ */
public function isHandling(array $record); public function isHandling(array $record);
@@ -46,7 +46,7 @@ interface HandlerInterface
* calling further handlers in the stack with a given log record. * calling further handlers in the stack with a given log record.
* *
* @param array $record The record to handle * @param array $record The record to handle
* @return Boolean true means that this handler handled the record, and that bubbling is not permitted. * @return bool true means that this handler handled the record, and that bubbling is not permitted.
* false means the record was either not processed or that this handler allows bubbling. * false means the record was either not processed or that this handler allows bubbling.
*/ */
public function handle(array $record); public function handle(array $record);

View File

@@ -33,7 +33,7 @@ class IFTTTHandler extends AbstractProcessingHandler
* @param string $eventName The name of the IFTTT Maker event that should be triggered * @param string $eventName The name of the IFTTT Maker event that should be triggered
* @param string $secretKey A valid IFTTT secret key * @param string $secretKey A valid IFTTT secret key
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true) public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true)
{ {

View File

@@ -0,0 +1,62 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Inspired on LogEntriesHandler.
*
* @author Robert Kaufmann III <rok3@rok3.me>
* @author Gabriel Machado <gabriel.ms1@hotmail.com>
*/
class InsightOpsHandler extends SocketHandler
{
/**
* @var string
*/
protected $logToken;
/**
* @param string $token Log token supplied by InsightOps
* @param string $region Region where InsightOps account is hosted. Could be 'us' or 'eu'.
* @param bool $useSSL Whether or not SSL encryption should be used
* @param int $level The minimum logging level to trigger this handler
* @param bool $bubble Whether or not messages that are handled should bubble up the stack.
*
* @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
*/
public function __construct($token, $region = 'us', $useSSL = true, $level = Logger::DEBUG, $bubble = true)
{
if ($useSSL && !extension_loaded('openssl')) {
throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
}
$endpoint = $useSSL
? 'ssl://' . $region . '.data.logs.insight.rapid7.com:443'
: $region . '.data.logs.insight.rapid7.com:80';
parent::__construct($endpoint, $level, $bubble);
$this->logToken = $token;
}
/**
* {@inheritdoc}
*
* @param array $record
* @return string
*/
protected function generateDataStream($record)
{
return $this->logToken . ' ' . $record['formatted'];
}
}

View File

@@ -27,7 +27,7 @@ class MandrillHandler extends MailHandler
* @param string $apiKey A valid Mandrill API key * @param string $apiKey A valid Mandrill API key
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true) public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true)
{ {

View File

@@ -84,7 +84,7 @@ class NewRelicHandler extends AbstractProcessingHandler
unset($record['formatted']['context']['transaction_name']); unset($record['formatted']['context']['transaction_name']);
} }
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) { if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
newrelic_notice_error($record['message'], $record['context']['exception']); newrelic_notice_error($record['message'], $record['context']['exception']);
unset($record['formatted']['context']['exception']); unset($record['formatted']['context']['exception']);
} else { } else {

View File

@@ -31,7 +31,7 @@ class PsrHandler extends AbstractHandler
/** /**
* @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied * @param LoggerInterface $logger The underlying PSR-3 compliant logger to which messages will be proxied
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true) public function __construct(LoggerInterface $logger, $level = Logger::DEBUG, $bubble = true)
{ {

View File

@@ -69,8 +69,8 @@ class PushoverHandler extends SocketHandler
* @param string|array $users Pushover user id or array of ids the message will be sent to * @param string|array $users Pushover user id or array of ids the message will be sent to
* @param string $title Title sent to the Pushover API * @param string $title Title sent to the Pushover API
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $useSSL Whether to connect via SSL. Required when pushing messages to users that are not * @param bool $useSSL Whether to connect via SSL. Required when pushing messages to users that are not
* the pushover.net app owner. OpenSSL is required for this option. * the pushover.net app owner. OpenSSL is required for this option.
* @param int $highPriorityLevel The minimum logging level at which this handler will start * @param int $highPriorityLevel The minimum logging level at which this handler will start
* sending "high priority" requests to the Pushover API * sending "high priority" requests to the Pushover API
@@ -180,6 +180,6 @@ class PushoverHandler extends SocketHandler
*/ */
public function useFormattedMessage($value) public function useFormattedMessage($value)
{ {
$this->useFormattedMessage = (boolean) $value; $this->useFormattedMessage = (bool) $value;
} }
} }

View File

@@ -57,7 +57,7 @@ class RavenHandler extends AbstractProcessingHandler
/** /**
* @param Raven_Client $ravenClient * @param Raven_Client $ravenClient
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true) public function __construct(Raven_Client $ravenClient, $level = Logger::DEBUG, $bubble = true)
{ {
@@ -180,7 +180,7 @@ class RavenHandler extends AbstractProcessingHandler
} }
if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) { if (isset($record['context']['exception']) && ($record['context']['exception'] instanceof \Exception || (PHP_VERSION_ID >= 70000 && $record['context']['exception'] instanceof \Throwable))) {
$options['extra']['message'] = $record['formatted']; $options['message'] = $record['formatted'];
$this->ravenClient->captureException($record['context']['exception'], $options); $this->ravenClient->captureException($record['context']['exception'], $options);
} else { } else {
$this->ravenClient->captureMessage($record['formatted'], array(), $options); $this->ravenClient->captureMessage($record['formatted'], array(), $options);

View File

@@ -39,9 +39,9 @@ class RotatingFileHandler extends StreamHandler
* @param string $filename * @param string $filename
* @param int $maxFiles The maximal amount of files to keep (0 means unlimited) * @param int $maxFiles The maximal amount of files to keep (0 means unlimited)
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
* @param Boolean $useLocking Try to lock log file before doing any writes * @param bool $useLocking Try to lock log file before doing any writes
*/ */
public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false) public function __construct($filename, $maxFiles = 0, $level = Logger::DEBUG, $bubble = true, $filePermission = null, $useLocking = false)
{ {
@@ -166,7 +166,7 @@ class RotatingFileHandler extends StreamHandler
$fileInfo = pathinfo($this->filename); $fileInfo = pathinfo($this->filename);
$glob = str_replace( $glob = str_replace(
array('{filename}', '{date}'), array('{filename}', '{date}'),
array($fileInfo['filename'], '*'), array($fileInfo['filename'], '[0-9][0-9][0-9][0-9]*'),
$fileInfo['dirname'] . '/' . $this->filenameFormat $fileInfo['dirname'] . '/' . $this->filenameFormat
); );
if (!empty($fileInfo['extension'])) { if (!empty($fileInfo['extension'])) {

8
src/Monolog/Handler/Slack/SlackRecord.php Normal file → Executable file
View File

@@ -146,7 +146,7 @@ class SlackRecord
if ($this->useShortAttachment) { if ($this->useShortAttachment) {
$attachment['fields'][] = $this->generateAttachmentField( $attachment['fields'][] = $this->generateAttachmentField(
ucfirst($key), $key,
$record[$key] $record[$key]
); );
} else { } else {
@@ -230,7 +230,7 @@ class SlackRecord
* Generates attachment field * Generates attachment field
* *
* @param string $title * @param string $title
* @param string|array $value\ * @param string|array $value
* *
* @return array * @return array
*/ */
@@ -241,7 +241,7 @@ class SlackRecord
: $value; : $value;
return array( return array(
'title' => $title, 'title' => ucfirst($title),
'value' => $value, 'value' => $value,
'short' => false 'short' => false
); );
@@ -257,7 +257,7 @@ class SlackRecord
private function generateAttachmentFields(array $data) private function generateAttachmentFields(array $data)
{ {
$fields = array(); $fields = array();
foreach ($data as $key => $value) { foreach ($this->normalizerFormatter->format($data) as $key => $value) {
$fields[] = $this->generateAttachmentField($key, $value); $fields[] = $this->generateAttachmentField($key, $value);
} }

View File

@@ -75,6 +75,11 @@ class SlackHandler extends SocketHandler
return $this->slackRecord; return $this->slackRecord;
} }
public function getToken()
{
return $this->token;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
* *

View File

@@ -70,6 +70,11 @@ class SlackWebhookHandler extends AbstractProcessingHandler
return $this->slackRecord; return $this->slackRecord;
} }
public function getWebhookUrl()
{
return $this->webhookUrl;
}
/** /**
* {@inheritdoc} * {@inheritdoc}
* *

View File

@@ -27,6 +27,7 @@ class SocketHandler extends AbstractProcessingHandler
private $timeout = 0; private $timeout = 0;
private $writingTimeout = 10; private $writingTimeout = 10;
private $lastSentBytes = null; private $lastSentBytes = null;
private $chunkSize = null;
private $persistent = false; private $persistent = false;
private $errno; private $errno;
private $errstr; private $errstr;
@@ -35,7 +36,7 @@ class SocketHandler extends AbstractProcessingHandler
/** /**
* @param string $connectionString Socket connection string * @param string $connectionString Socket connection string
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true) public function __construct($connectionString, $level = Logger::DEBUG, $bubble = true)
{ {
@@ -87,7 +88,7 @@ class SocketHandler extends AbstractProcessingHandler
*/ */
public function setPersistent($persistent) public function setPersistent($persistent)
{ {
$this->persistent = (boolean) $persistent; $this->persistent = (bool) $persistent;
} }
/** /**
@@ -127,6 +128,16 @@ class SocketHandler extends AbstractProcessingHandler
$this->writingTimeout = (float) $seconds; $this->writingTimeout = (float) $seconds;
} }
/**
* Set chunk size. Only has effect during connection in the writing cycle.
*
* @param float $bytes
*/
public function setChunkSize($bytes)
{
$this->chunkSize = $bytes;
}
/** /**
* Get current connection string * Get current connection string
* *
@@ -177,6 +188,16 @@ class SocketHandler extends AbstractProcessingHandler
return $this->writingTimeout; return $this->writingTimeout;
} }
/**
* Get current chunk size
*
* @return float
*/
public function getChunkSize()
{
return $this->chunkSize;
}
/** /**
* Check to see if the socket is currently available. * Check to see if the socket is currently available.
* *
@@ -219,6 +240,16 @@ class SocketHandler extends AbstractProcessingHandler
return stream_set_timeout($this->resource, $seconds, $microseconds); return stream_set_timeout($this->resource, $seconds, $microseconds);
} }
/**
* Wrapper to allow mocking
*
* @see http://php.net/manual/en/function.stream-set-chunk-size.php
*/
protected function streamSetChunkSize()
{
return stream_set_chunk_size($this->resource, $this->chunkSize);
}
/** /**
* Wrapper to allow mocking * Wrapper to allow mocking
*/ */
@@ -268,6 +299,7 @@ class SocketHandler extends AbstractProcessingHandler
{ {
$this->createSocketResource(); $this->createSocketResource();
$this->setSocketTimeout(); $this->setSocketTimeout();
$this->setStreamChunkSize();
} }
private function createSocketResource() private function createSocketResource()
@@ -290,6 +322,13 @@ class SocketHandler extends AbstractProcessingHandler
} }
} }
private function setStreamChunkSize()
{
if ($this->chunkSize && !$this->streamSetChunkSize()) {
throw new \UnexpectedValueException("Failed setting chunk size with stream_set_chunk_size()");
}
}
private function writeToSocket($data) private function writeToSocket($data)
{ {
$length = strlen($data); $length = strlen($data);

View File

@@ -32,9 +32,9 @@ class StreamHandler extends AbstractProcessingHandler
/** /**
* @param resource|string $stream * @param resource|string $stream
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write) * @param int|null $filePermission Optional file permissions (default (0644) are only for owner read/write)
* @param Boolean $useLocking Try to lock log file before doing any writes * @param bool $useLocking Try to lock log file before doing any writes
* *
* @throws \Exception If a missing directory is not buildable * @throws \Exception If a missing directory is not buildable
* @throws \InvalidArgumentException If stream is not a resource or string * @throws \InvalidArgumentException If stream is not a resource or string
@@ -167,7 +167,7 @@ class StreamHandler extends AbstractProcessingHandler
set_error_handler(array($this, 'customErrorHandler')); set_error_handler(array($this, 'customErrorHandler'));
$status = mkdir($dir, 0777, true); $status = mkdir($dir, 0777, true);
restore_error_handler(); restore_error_handler();
if (false === $status) { if (false === $status && !is_dir($dir)) {
throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir)); throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage, $dir));
} }
} }

View File

@@ -12,6 +12,7 @@
namespace Monolog\Handler; namespace Monolog\Handler;
use Monolog\Logger; use Monolog\Logger;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\LineFormatter; use Monolog\Formatter\LineFormatter;
use Swift; use Swift;
@@ -29,7 +30,7 @@ class SwiftMailerHandler extends MailHandler
* @param \Swift_Mailer $mailer The mailer to use * @param \Swift_Mailer $mailer The mailer to use
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced * @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/ */
public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true) public function __construct(\Swift_Mailer $mailer, $message, $level = Logger::ERROR, $bubble = true)
{ {
@@ -47,6 +48,17 @@ class SwiftMailerHandler extends MailHandler
$this->mailer->send($this->buildMessage($content, $records)); $this->mailer->send($this->buildMessage($content, $records));
} }
/**
* Gets the formatter for the Swift_Message subject.
*
* @param string $format The format of the subject
* @return FormatterInterface
*/
protected function getSubjectFormatter($format)
{
return new LineFormatter($format);
}
/** /**
* Creates instance of Swift_Message to be sent * Creates instance of Swift_Message to be sent
* *
@@ -69,7 +81,7 @@ class SwiftMailerHandler extends MailHandler
} }
if ($records) { if ($records) {
$subjectFormatter = new LineFormatter($message->getSubject()); $subjectFormatter = $this->getSubjectFormatter($message->getSubject());
$message->setSubject($subjectFormatter->format($this->getHighestRecord($records))); $message->setSubject($subjectFormatter->format($this->getHighestRecord($records)));
} }

View File

@@ -35,7 +35,7 @@ class SyslogHandler extends AbstractSyslogHandler
* @param string $ident * @param string $ident
* @param mixed $facility * @param mixed $facility
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param int $logopts Option flags for the openlog() call, defaults to LOG_PID * @param int $logopts Option flags for the openlog() call, defaults to LOG_PID
*/ */
public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID) public function __construct($ident, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $logopts = LOG_PID)

View File

@@ -29,7 +29,7 @@ class SyslogUdpHandler extends AbstractSyslogHandler
* @param int $port * @param int $port
* @param mixed $facility * @param mixed $facility
* @param int $level The minimum logging level at which this handler will be triggered * @param int $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not * @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param string $ident Program name or tag for each log message. * @param string $ident Program name or tag for each log message.
*/ */
public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php') public function __construct($host, $port = 514, $facility = LOG_USER, $level = Logger::DEBUG, $bubble = true, $ident = 'php')

View File

@@ -48,6 +48,16 @@ class WhatFailureGroupHandler extends GroupHandler
*/ */
public function handleBatch(array $records) public function handleBatch(array $records)
{ {
if ($this->processors) {
$processed = array();
foreach ($records as $record) {
foreach ($this->processors as $processor) {
$processed[] = call_user_func($processor, $record);
}
}
$records = $processed;
}
foreach ($this->handlers as $handler) { foreach ($this->handlers as $handler) {
try { try {
$handler->handleBatch($records); $handler->handleBatch($records);

View File

@@ -15,6 +15,7 @@ use Monolog\Handler\HandlerInterface;
use Monolog\Handler\StreamHandler; use Monolog\Handler\StreamHandler;
use Psr\Log\LoggerInterface; use Psr\Log\LoggerInterface;
use Psr\Log\InvalidArgumentException; use Psr\Log\InvalidArgumentException;
use Exception;
/** /**
* Monolog log channel * Monolog log channel
@@ -133,6 +134,11 @@ class Logger implements LoggerInterface
*/ */
protected $microsecondTimestamps = true; protected $microsecondTimestamps = true;
/**
* @var callable
*/
protected $exceptionHandler;
/** /**
* @param string $name The logging channel * @param string $name The logging channel
* @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc. * @param HandlerInterface[] $handlers Optional stack of handlers, the first one in the array is called first, etc.
@@ -141,7 +147,7 @@ class Logger implements LoggerInterface
public function __construct($name, array $handlers = array(), array $processors = array()) public function __construct($name, array $handlers = array(), array $processors = array())
{ {
$this->name = $name; $this->name = $name;
$this->handlers = $handlers; $this->setHandlers($handlers);
$this->processors = $processors; $this->processors = $processors;
} }
@@ -281,7 +287,7 @@ class Logger implements LoggerInterface
* @param int $level The logging level * @param int $level The logging level
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addRecord($level, $message, array $context = array()) public function addRecord($level, $message, array $context = array())
{ {
@@ -329,6 +335,7 @@ class Logger implements LoggerInterface
'extra' => array(), 'extra' => array(),
); );
try {
foreach ($this->processors as $processor) { foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record); $record = call_user_func($processor, $record);
} }
@@ -340,6 +347,9 @@ class Logger implements LoggerInterface
next($this->handlers); next($this->handlers);
} }
} catch (Exception $e) {
$this->handleException($e, $record);
}
return true; return true;
} }
@@ -349,7 +359,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addDebug($message, array $context = array()) public function addDebug($message, array $context = array())
{ {
@@ -361,7 +371,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addInfo($message, array $context = array()) public function addInfo($message, array $context = array())
{ {
@@ -373,7 +383,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addNotice($message, array $context = array()) public function addNotice($message, array $context = array())
{ {
@@ -385,7 +395,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addWarning($message, array $context = array()) public function addWarning($message, array $context = array())
{ {
@@ -397,7 +407,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addError($message, array $context = array()) public function addError($message, array $context = array())
{ {
@@ -409,7 +419,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addCritical($message, array $context = array()) public function addCritical($message, array $context = array())
{ {
@@ -421,7 +431,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addAlert($message, array $context = array()) public function addAlert($message, array $context = array())
{ {
@@ -433,7 +443,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function addEmergency($message, array $context = array()) public function addEmergency($message, array $context = array())
{ {
@@ -484,7 +494,7 @@ class Logger implements LoggerInterface
* Checks whether the Logger has a handler that listens on the given level * Checks whether the Logger has a handler that listens on the given level
* *
* @param int $level * @param int $level
* @return Boolean * @return bool
*/ */
public function isHandling($level) public function isHandling($level)
{ {
@@ -501,6 +511,43 @@ class Logger implements LoggerInterface
return false; return false;
} }
/**
* Set a custom exception handler
*
* @param callable $callback
* @return $this
*/
public function setExceptionHandler($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException('Exception handler must be valid callable (callback or object with an __invoke method), '.var_export($callback, true).' given');
}
$this->exceptionHandler = $callback;
return $this;
}
/**
* @return callable
*/
public function getExceptionHandler()
{
return $this->exceptionHandler;
}
/**
* Delegates exception management to the custom exception handler,
* or throws the exception if no custom handler is set.
*/
protected function handleException(Exception $e, array $record)
{
if (!$this->exceptionHandler) {
throw $e;
}
call_user_func($this->exceptionHandler, $e, $record);
}
/** /**
* Adds a log record at an arbitrary level. * Adds a log record at an arbitrary level.
* *
@@ -509,7 +556,7 @@ class Logger implements LoggerInterface
* @param mixed $level The log level * @param mixed $level The log level
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function log($level, $message, array $context = array()) public function log($level, $message, array $context = array())
{ {
@@ -525,7 +572,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function debug($message, array $context = array()) public function debug($message, array $context = array())
{ {
@@ -539,7 +586,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function info($message, array $context = array()) public function info($message, array $context = array())
{ {
@@ -553,7 +600,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function notice($message, array $context = array()) public function notice($message, array $context = array())
{ {
@@ -567,7 +614,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function warn($message, array $context = array()) public function warn($message, array $context = array())
{ {
@@ -581,7 +628,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function warning($message, array $context = array()) public function warning($message, array $context = array())
{ {
@@ -595,7 +642,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function err($message, array $context = array()) public function err($message, array $context = array())
{ {
@@ -609,7 +656,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function error($message, array $context = array()) public function error($message, array $context = array())
{ {
@@ -623,7 +670,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function crit($message, array $context = array()) public function crit($message, array $context = array())
{ {
@@ -637,7 +684,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function critical($message, array $context = array()) public function critical($message, array $context = array())
{ {
@@ -651,7 +698,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function alert($message, array $context = array()) public function alert($message, array $context = array())
{ {
@@ -665,7 +712,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function emerg($message, array $context = array()) public function emerg($message, array $context = array())
{ {
@@ -679,7 +726,7 @@ class Logger implements LoggerInterface
* *
* @param string $message The log message * @param string $message The log message
* @param array $context The log context * @param array $context The log context
* @return Boolean Whether the record has been processed * @return bool Whether the record has been processed
*/ */
public function emergency($message, array $context = array()) public function emergency($message, array $context = array())
{ {

View File

@@ -34,8 +34,8 @@ abstract class MemoryProcessor
*/ */
public function __construct($realUsage = true, $useFormatting = true) public function __construct($realUsage = true, $useFormatting = true)
{ {
$this->realUsage = (boolean) $realUsage; $this->realUsage = (bool) $realUsage;
$this->useFormatting = (boolean) $useFormatting; $this->useFormatting = (bool) $useFormatting;
} }
/** /**

View File

@@ -40,7 +40,7 @@ class FluentdFormatterTest extends TestCase
$formatter = new FluentdFormatter(); $formatter = new FluentdFormatter();
$this->assertEquals( $this->assertEquals(
'["test",0,{"message":"test","extra":[],"level":300,"level_name":"WARNING"}]', '["test",0,{"message":"test","context":[],"extra":[],"level":300,"level_name":"WARNING"}]',
$formatter->format($record) $formatter->format($record)
); );
} }
@@ -55,7 +55,7 @@ class FluentdFormatterTest extends TestCase
$formatter = new FluentdFormatter(true); $formatter = new FluentdFormatter(true);
$this->assertEquals( $this->assertEquals(
'["test.error",0,{"message":"test","extra":[]}]', '["test.error",0,{"message":"test","context":[],"extra":[]}]',
$formatter->format($record) $formatter->format($record)
); );
} }

View File

@@ -180,4 +180,40 @@ class JsonFormatterTest extends TestCase
'}'; '}';
return $formattedException; return $formattedException;
} }
public function testNormalizeHandleLargeArraysWithExactly1000Items()
{
$formatter = new NormalizerFormatter();
$largeArray = range(1, 1000);
$res = $formatter->format(array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array($largeArray),
'datetime' => new \DateTime,
'extra' => array(),
));
$this->assertCount(1000, $res['context'][0]);
$this->assertArrayNotHasKey('...', $res['context'][0]);
}
public function testNormalizeHandleLargeArrays()
{
$formatter = new NormalizerFormatter();
$largeArray = range(1, 2000);
$res = $formatter->format(array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array($largeArray),
'datetime' => new \DateTime,
'extra' => array(),
));
$this->assertCount(1001, $res['context'][0]);
$this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']);
}
} }

View File

@@ -193,6 +193,15 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(@json_encode(array($foo, $bar)), $res); $this->assertEquals(@json_encode(array($foo, $bar)), $res);
} }
public function testCanNormalizeReferences()
{
$formatter = new NormalizerFormatter();
$x = array('foo' => 'bar');
$y = array('x' => &$x);
$x['y'] = &$y;
$formatter->format($y);
}
public function testIgnoresInvalidTypes() public function testIgnoresInvalidTypes()
{ {
// set up the recursion // set up the recursion
@@ -217,6 +226,24 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
$this->assertEquals(@json_encode(array($resource)), $res); $this->assertEquals(@json_encode(array($resource)), $res);
} }
public function testNormalizeHandleLargeArraysWithExactly1000Items()
{
$formatter = new NormalizerFormatter();
$largeArray = range(1, 1000);
$res = $formatter->format(array(
'level_name' => 'CRITICAL',
'channel' => 'test',
'message' => 'bar',
'context' => array($largeArray),
'datetime' => new \DateTime,
'extra' => array(),
));
$this->assertCount(1000, $res['context'][0]);
$this->assertArrayNotHasKey('...', $res['context'][0]);
}
public function testNormalizeHandleLargeArrays() public function testNormalizeHandleLargeArrays()
{ {
$formatter = new NormalizerFormatter(); $formatter = new NormalizerFormatter();
@@ -231,7 +258,7 @@ class NormalizerFormatterTest extends \PHPUnit_Framework_TestCase
'extra' => array(), 'extra' => array(),
)); ));
$this->assertCount(1000, $res['context'][0]); $this->assertCount(1001, $res['context'][0]);
$this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']); $this->assertEquals('Over 1000 items (2000 total), aborting normalization', $res['context'][0]['...']);
} }

View File

@@ -0,0 +1,80 @@
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\TestCase;
use Monolog\Logger;
/**
* @author Robert Kaufmann III <rok3@rok3.me>
* @author Gabriel Machado <gabriel.ms1@hotmail.com>
*/
class InsightOpsHandlerTest extends TestCase
{
/**
* @var resource
*/
private $resource;
/**
* @var LogEntriesHandler
*/
private $handler;
public function testWriteContent()
{
$this->createHandler();
$this->handler->handle($this->getRecord(Logger::CRITICAL, 'Critical write test'));
fseek($this->resource, 0);
$content = fread($this->resource, 1024);
$this->assertRegexp('/testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] test.CRITICAL: Critical write test/', $content);
}
public function testWriteBatchContent()
{
$this->createHandler();
$this->handler->handleBatch($this->getMultipleRecords());
fseek($this->resource, 0);
$content = fread($this->resource, 1024);
$this->assertRegexp('/(testToken \[\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\] .* \[\] \[\]\n){3}/', $content);
}
private function createHandler()
{
$useSSL = extension_loaded('openssl');
$args = array('testToken', 'us', $useSSL, Logger::DEBUG, true);
$this->resource = fopen('php://memory', 'a');
$this->handler = $this->getMock(
'\Monolog\Handler\InsightOpsHandler',
array('fsockopen', 'streamSetTimeout', 'closeSocket'),
$args
);
$reflectionProperty = new \ReflectionProperty('\Monolog\Handler\SocketHandler', 'connectionString');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($this->handler, 'localhost:1234');
$this->handler->expects($this->any())
->method('fsockopen')
->will($this->returnValue($this->resource));
$this->handler->expects($this->any())
->method('streamSetTimeout')
->will($this->returnValue(true));
$this->handler->expects($this->any())
->method('closeSocket')
->will($this->returnValue(true));
}
}

View File

@@ -191,6 +191,40 @@ class RotatingFileHandlerTest extends TestCase
); );
} }
/**
* @dataProvider rotationWhenSimilarFilesExistTests
*/
public function testRotationWhenSimilarFileNamesExist($dateFormat)
{
touch($old1 = __DIR__.'/Fixtures/foo-foo-'.date($dateFormat).'.rot');
touch($old2 = __DIR__.'/Fixtures/foo-bar-'.date($dateFormat).'.rot');
$log = __DIR__.'/Fixtures/foo-'.date($dateFormat).'.rot';
$handler = new RotatingFileHandler(__DIR__.'/Fixtures/foo.rot', 2);
$handler->setFormatter($this->getIdentityFormatter());
$handler->setFilenameFormat('{filename}-{date}', $dateFormat);
$handler->handle($this->getRecord());
$handler->close();
$this->assertTrue(file_exists($log));
}
public function rotationWhenSimilarFilesExistTests()
{
return array(
'Rotation is triggered when the file of the current day is not present but similar exists'
=> array(RotatingFileHandler::FILE_PER_DAY),
'Rotation is triggered when the file of the current month is not present but similar exists'
=> array(RotatingFileHandler::FILE_PER_MONTH),
'Rotation is triggered when the file of the current year is not present but similar exists'
=> array(RotatingFileHandler::FILE_PER_YEAR),
);
}
public function testReuseCurrentFile() public function testReuseCurrentFile()
{ {
$log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot'; $log = __DIR__.'/Fixtures/foo-'.date('Y-m-d').'.rot';

View File

@@ -320,12 +320,12 @@ class SlackRecordTest extends TestCase
'short' => false, 'short' => false,
), ),
array( array(
'title' => 'tags', 'title' => 'Tags',
'value' => sprintf('```%s```', json_encode($extra['tags'])), 'value' => sprintf('```%s```', json_encode($extra['tags'])),
'short' => false 'short' => false
), ),
array( array(
'title' => 'test', 'title' => 'Test',
'value' => $context['test'], 'value' => $context['test'],
'short' => false 'short' => false
) )
@@ -353,6 +353,14 @@ class SlackRecordTest extends TestCase
$this->assertSame($record['datetime']->getTimestamp(), $attachment['ts']); $this->assertSame($record['datetime']->getTimestamp(), $attachment['ts']);
} }
public function testContextHasException()
{
$record = $this->getRecord(Logger::CRITICAL, 'This is a critical message.', array('exception' => new \Exception()));
$slackRecord = new SlackRecord(null, null, true, null, false, true);
$data = $slackRecord->getSlackData($record);
$this->assertInternalType('string', $data['attachments'][0]['fields'][1]['value']);
}
public function testExcludeExtraAndContextFields() public function testExcludeExtraAndContextFields()
{ {
$record = $this->getRecord( $record = $this->getRecord(
@@ -368,12 +376,12 @@ class SlackRecordTest extends TestCase
$expected = array( $expected = array(
array( array(
'title' => 'info', 'title' => 'Info',
'value' => sprintf('```%s```', json_encode(array('author' => 'Jordi'), $this->jsonPrettyPrintFlag)), 'value' => sprintf('```%s```', json_encode(array('author' => 'Jordi'), $this->jsonPrettyPrintFlag)),
'short' => false 'short' => false
), ),
array( array(
'title' => 'tags', 'title' => 'Tags',
'value' => sprintf('```%s```', json_encode(array('web'))), 'value' => sprintf('```%s```', json_encode(array('web'))),
'short' => false 'short' => false
), ),

View File

@@ -77,6 +77,13 @@ class SocketHandlerTest extends TestCase
$this->assertEquals(10.25, $this->handler->getWritingTimeout()); $this->assertEquals(10.25, $this->handler->getWritingTimeout());
} }
public function testSetChunkSize()
{
$this->createHandler('localhost:1234');
$this->handler->setChunkSize(1025);
$this->assertEquals(1025, $this->handler->getChunkSize());
}
public function testSetConnectionString() public function testSetConnectionString()
{ {
$this->createHandler('tcp://localhost:9090'); $this->createHandler('tcp://localhost:9090');
@@ -120,6 +127,19 @@ class SocketHandlerTest extends TestCase
$this->writeRecord('Hello world'); $this->writeRecord('Hello world');
} }
/**
* @expectedException UnexpectedValueException
*/
public function testExceptionIsThrownIfCannotSetChunkSize()
{
$this->setMockHandler(array('streamSetChunkSize'));
$this->handler->setChunkSize(8192);
$this->handler->expects($this->once())
->method('streamSetChunkSize')
->will($this->returnValue(false));
$this->writeRecord('Hello world');
}
/** /**
* @expectedException RuntimeException * @expectedException RuntimeException
*/ */
@@ -304,6 +324,12 @@ class SocketHandlerTest extends TestCase
->will($this->returnValue(true)); ->will($this->returnValue(true));
} }
if (!in_array('streamSetChunkSize', $methods)) {
$this->handler->expects($this->any())
->method('streamSetChunkSize')
->will($this->returnValue(8192));
}
$this->handler->setFormatter($this->getIdentityFormatter()); $this->handler->setFormatter($this->getIdentityFormatter());
} }
} }

View File

@@ -87,6 +87,29 @@ class WhatFailureGroupHandlerTest extends TestCase
$this->assertTrue($records[0]['extra']['foo']); $this->assertTrue($records[0]['extra']['foo']);
} }
/**
* @covers Monolog\Handler\WhatFailureGroupHandler::handleBatch
*/
public function testHandleBatchUsesProcessors()
{
$testHandlers = array(new TestHandler(), new TestHandler());
$handler = new WhatFailureGroupHandler($testHandlers);
$handler->pushProcessor(function ($record) {
$record['extra']['foo'] = true;
return $record;
});
$handler->handleBatch(array($this->getRecord(Logger::DEBUG), $this->getRecord(Logger::INFO)));
foreach ($testHandlers as $test) {
$this->assertTrue($test->hasDebugRecords());
$this->assertTrue($test->hasInfoRecords());
$this->assertTrue(count($test->getRecords()) === 2);
$records = $test->getRecords();
$this->assertTrue($records[0]['extra']['foo']);
$this->assertTrue($records[1]['extra']['foo']);
}
}
/** /**
* @covers Monolog\Handler\WhatFailureGroupHandler::handle * @covers Monolog\Handler\WhatFailureGroupHandler::handle
*/ */

View File

@@ -545,4 +545,73 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
'without microseconds' => array(false, PHP_VERSION_ID >= 70100 ? 'assertNotSame' : 'assertSame'), 'without microseconds' => array(false, PHP_VERSION_ID >= 70100 ? 'assertNotSame' : 'assertSame'),
); );
} }
/**
* @covers Monolog\Logger::setExceptionHandler
*/
public function testSetExceptionHandler()
{
$logger = new Logger(__METHOD__);
$this->assertNull($logger->getExceptionHandler());
$callback = function ($ex) {
};
$logger->setExceptionHandler($callback);
$this->assertEquals($callback, $logger->getExceptionHandler());
}
/**
* @covers Monolog\Logger::setExceptionHandler
* @expectedException InvalidArgumentException
*/
public function testBadExceptionHandlerType()
{
$logger = new Logger(__METHOD__);
$logger->setExceptionHandler(false);
}
/**
* @covers Monolog\Logger::handleException
* @expectedException Exception
*/
public function testDefaultHandleException()
{
$logger = new Logger(__METHOD__);
$handler = $this->getMock('Monolog\Handler\HandlerInterface');
$handler->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler->expects($this->any())
->method('handle')
->will($this->throwException(new \Exception('Some handler exception')))
;
$logger->pushHandler($handler);
$logger->info('test');
}
/**
* @covers Monolog\Logger::handleException
* @covers Monolog\Logger::addRecord
*/
public function testCustomHandleException()
{
$logger = new Logger(__METHOD__);
$that = $this;
$logger->setExceptionHandler(function ($e, $record) use ($that) {
$that->assertEquals($e->getMessage(), 'Some handler exception');
$that->assertTrue(is_array($record));
$that->assertEquals($record['message'], 'test');
});
$handler = $this->getMock('Monolog\Handler\HandlerInterface');
$handler->expects($this->any())
->method('isHandling')
->will($this->returnValue(true))
;
$handler->expects($this->any())
->method('handle')
->will($this->throwException(new \Exception('Some handler exception')))
;
$logger->pushHandler($handler);
$logger->info('test');
}
} }