mirror of
https://github.com/Seldaek/monolog.git
synced 2025-07-31 10:20:14 +02:00
Merge branch '1.x'
This commit is contained in:
@@ -189,6 +189,9 @@ $logger->pushHandler($firephp);
|
||||
$securityLogger = new Logger('security');
|
||||
$securityLogger->pushHandler($stream);
|
||||
$securityLogger->pushHandler($firephp);
|
||||
|
||||
// Or clone the first one to only change the channel
|
||||
$securityLogger = $logger->withName('security');
|
||||
```
|
||||
|
||||
## Customizing the log format
|
||||
|
@@ -105,6 +105,8 @@
|
||||
- _PsrHandler_: Can be used to forward log records to an existing PSR-3 logger
|
||||
- _TestHandler_: Used for testing, it records everything that is sent to it and
|
||||
has accessors to read out the information.
|
||||
- _HandlerWrapper_: A simple handler wrapper you can inherit from to create
|
||||
your own wrappers easily.
|
||||
|
||||
## Formatters
|
||||
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Encodes whatever record data is passed to it as json
|
||||
*
|
||||
@@ -18,13 +20,17 @@ namespace Monolog\Formatter;
|
||||
*
|
||||
* @author Jordi Boggiano <j.boggiano@seld.be>
|
||||
*/
|
||||
class JsonFormatter implements FormatterInterface
|
||||
class JsonFormatter extends NormalizerFormatter
|
||||
{
|
||||
const BATCH_MODE_JSON = 1;
|
||||
const BATCH_MODE_NEWLINES = 2;
|
||||
|
||||
protected $batchMode;
|
||||
protected $appendNewline;
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $includeStacktraces = false;
|
||||
|
||||
/**
|
||||
* @param int $batchMode
|
||||
@@ -64,7 +70,7 @@ class JsonFormatter implements FormatterInterface
|
||||
*/
|
||||
public function format(array $record)
|
||||
{
|
||||
return json_encode($record) . ($this->appendNewline ? "\n" : '');
|
||||
return $this->toJson($this->normalize($record), true) . ($this->appendNewline ? "\n" : '');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,6 +88,14 @@ class JsonFormatter implements FormatterInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $include
|
||||
*/
|
||||
public function includeStacktraces($include = true)
|
||||
{
|
||||
$this->includeStacktraces = $include;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a JSON-encoded array of records.
|
||||
*
|
||||
@@ -90,7 +104,7 @@ class JsonFormatter implements FormatterInterface
|
||||
*/
|
||||
protected function formatBatchJson(array $records)
|
||||
{
|
||||
return json_encode($records);
|
||||
return $this->toJson($this->normalize($records), true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,4 +127,76 @@ class JsonFormatter implements FormatterInterface
|
||||
|
||||
return implode("\n", $records);
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes given $data.
|
||||
*
|
||||
* @param mixed $data
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
protected function normalize($data)
|
||||
{
|
||||
if (is_array($data) || $data instanceof \Traversable) {
|
||||
$normalized = array();
|
||||
|
||||
$count = 1;
|
||||
foreach ($data as $key => $value) {
|
||||
if ($count++ >= 1000) {
|
||||
$normalized['...'] = 'Over 1000 items, aborting normalization';
|
||||
break;
|
||||
}
|
||||
$normalized[$key] = $this->normalize($value);
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
}
|
||||
|
||||
if ($data instanceof Exception) {
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes given exception with or without its own stack trace based on
|
||||
* `includeStacktraces` property.
|
||||
*
|
||||
* @param Exception|Throwable $e
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'class' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
'code' => $e->getCode(),
|
||||
'file' => $e->getFile().':'.$e->getLine(),
|
||||
);
|
||||
|
||||
if ($this->includeStacktraces) {
|
||||
$trace = $e->getTrace();
|
||||
foreach ($trace as $frame) {
|
||||
if (isset($frame['file'])) {
|
||||
$data['trace'][] = $frame['file'].':'.$frame['line'];
|
||||
} else {
|
||||
// We should again normalize the frames, because it might contain invalid items
|
||||
$data['trace'][] = $this->normalize($frame);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($previous = $e->getPrevious()) {
|
||||
$data['previous'] = $this->normalizeException($previous);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
|
@@ -11,8 +11,6 @@
|
||||
|
||||
namespace Monolog\Formatter;
|
||||
|
||||
use Exception;
|
||||
|
||||
/**
|
||||
* Formats incoming records into a one-line string
|
||||
*
|
||||
@@ -78,6 +76,13 @@ class LineFormatter extends NormalizerFormatter
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($vars['context'] as $var => $val) {
|
||||
if (false !== strpos($output, '%context.'.$var.'%')) {
|
||||
$output = str_replace('%context.'.$var.'%', $this->stringify($val), $output);
|
||||
unset($vars['context'][$var]);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->ignoreEmptyContextAndExtra) {
|
||||
if (empty($vars['context'])) {
|
||||
unset($vars['context']);
|
||||
@@ -114,8 +119,13 @@ class LineFormatter extends NormalizerFormatter
|
||||
return $this->replaceNewlines($this->convertToString($value));
|
||||
}
|
||||
|
||||
protected function normalizeException(Exception $e)
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof \Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$previousText = '';
|
||||
if ($previous = $e->getPrevious()) {
|
||||
do {
|
||||
|
@@ -90,7 +90,8 @@ class NormalizerFormatter implements FormatterInterface
|
||||
}
|
||||
|
||||
if (is_object($data)) {
|
||||
if ($data instanceof Exception) {
|
||||
// TODO 2.0 only check for Throwable
|
||||
if ($data instanceof Exception || (PHP_VERSION_ID > 70000 && $data instanceof \Throwable)) {
|
||||
return $this->normalizeException($data);
|
||||
}
|
||||
|
||||
@@ -112,8 +113,13 @@ class NormalizerFormatter implements FormatterInterface
|
||||
return '[unknown('.gettype($data).')]';
|
||||
}
|
||||
|
||||
protected function normalizeException(Exception $e)
|
||||
protected function normalizeException($e)
|
||||
{
|
||||
// TODO 2.0 only check for Throwable
|
||||
if (!$e instanceof Exception && !$e instanceof \Throwable) {
|
||||
throw new \InvalidArgumentException('Exception/Throwable expected, got '.gettype($e).' / '.get_class($e));
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'class' => get_class($e),
|
||||
'message' => $e->getMessage(),
|
||||
|
@@ -70,6 +70,15 @@ abstract class AbstractSyslogHandler extends AbstractProcessingHandler
|
||||
$this->facilities['local5'] = LOG_LOCAL5;
|
||||
$this->facilities['local6'] = LOG_LOCAL6;
|
||||
$this->facilities['local7'] = LOG_LOCAL7;
|
||||
} else {
|
||||
$this->facilities['local0'] = 128; // LOG_LOCAL0
|
||||
$this->facilities['local1'] = 136; // LOG_LOCAL1
|
||||
$this->facilities['local2'] = 144; // LOG_LOCAL2
|
||||
$this->facilities['local3'] = 152; // LOG_LOCAL3
|
||||
$this->facilities['local4'] = 160; // LOG_LOCAL4
|
||||
$this->facilities['local5'] = 168; // LOG_LOCAL5
|
||||
$this->facilities['local6'] = 176; // LOG_LOCAL6
|
||||
$this->facilities['local7'] = 184; // LOG_LOCAL7
|
||||
}
|
||||
|
||||
// convert textual description of facility to syslog constant
|
||||
|
@@ -55,18 +55,12 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
protected function write(array $record)
|
||||
{
|
||||
$data = $record["formatted"];
|
||||
|
||||
$routingKey = sprintf(
|
||||
'%s.%s',
|
||||
// TODO 2.0 remove substr call
|
||||
substr($record['level_name'], 0, 4),
|
||||
$record['channel']
|
||||
);
|
||||
$routingKey = $this->getRoutingKey($record);
|
||||
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
$this->exchange->publish(
|
||||
$data,
|
||||
strtolower($routingKey),
|
||||
$routingKey,
|
||||
0,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
@@ -75,19 +69,74 @@ class AmqpHandler extends AbstractProcessingHandler
|
||||
);
|
||||
} else {
|
||||
$this->exchange->basic_publish(
|
||||
new AMQPMessage(
|
||||
(string) $data,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
)
|
||||
),
|
||||
$this->createAmqpMessage($data),
|
||||
$this->exchangeName,
|
||||
strtolower($routingKey)
|
||||
$routingKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
if ($this->exchange instanceof AMQPExchange) {
|
||||
parent::handleBatch($records);
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($records as $record) {
|
||||
if (!$this->isHandling($record)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$record = $this->processRecord($record);
|
||||
$data = $this->getFormatter()->format($record);
|
||||
|
||||
$this->exchange->batch_basic_publish(
|
||||
$this->createAmqpMessage($data),
|
||||
$this->exchangeName,
|
||||
$this->getRoutingKey($record)
|
||||
);
|
||||
}
|
||||
|
||||
$this->exchange->publish_batch();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the routing key for the AMQP exchange
|
||||
*
|
||||
* @param array $record
|
||||
* @return string
|
||||
*/
|
||||
private function getRoutingKey(array $record)
|
||||
{
|
||||
$routingKey = sprintf(
|
||||
'%s.%s',
|
||||
// TODO 2.0 remove substr call
|
||||
substr($record['level_name'], 0, 4),
|
||||
$record['channel']
|
||||
);
|
||||
|
||||
return strtolower($routingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $data
|
||||
* @return AMQPMessage
|
||||
*/
|
||||
private function createAmqpMessage($data)
|
||||
{
|
||||
return new AMQPMessage(
|
||||
(string) $data,
|
||||
array(
|
||||
'delivery_mode' => 2,
|
||||
'content_type' => 'application/json',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
|
@@ -46,9 +46,9 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
self::$records[] = $record;
|
||||
|
||||
// Register shutdown handler if not already done
|
||||
if (PHP_SAPI !== 'cli' && !self::$initialized) {
|
||||
if (!self::$initialized) {
|
||||
self::$initialized = true;
|
||||
register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
|
||||
$this->registerShutdownFunction();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,26 +58,16 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
public static function send()
|
||||
{
|
||||
$htmlTags = true;
|
||||
// Check content type
|
||||
foreach (headers_list() as $header) {
|
||||
if (stripos($header, 'content-type:') === 0) {
|
||||
// This handler only works with HTML and javascript outputs
|
||||
// text/javascript is obsolete in favour of application/javascript, but still used
|
||||
if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
|
||||
$htmlTags = false;
|
||||
} elseif (stripos($header, 'text/html') === false) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
$format = self::getResponseFormat();
|
||||
if ($format === 'unknown') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (count(self::$records)) {
|
||||
if ($htmlTags) {
|
||||
echo '<script>' , self::generateScript() , '</script>';
|
||||
} else {
|
||||
echo self::generateScript();
|
||||
if ($format === 'html') {
|
||||
self::writeOutput('<script>' , self::generateScript() , '</script>');
|
||||
} elseif ($format === 'js') {
|
||||
self::writeOutput(self::generateScript());
|
||||
}
|
||||
self::reset();
|
||||
}
|
||||
@@ -91,6 +81,50 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
|
||||
self::$records = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for register_shutdown_function to allow overriding
|
||||
*/
|
||||
protected function registerShutdownFunction()
|
||||
{
|
||||
if (PHP_SAPI !== 'cli') {
|
||||
register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for echo to allow overriding
|
||||
*
|
||||
* @param string $str
|
||||
*/
|
||||
protected static function writeOutput($str)
|
||||
{
|
||||
echo $str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the format of the response
|
||||
*
|
||||
* @return string One of 'js', 'html' or 'unknown'
|
||||
*/
|
||||
protected static function getResponseFormat()
|
||||
{
|
||||
// Check content type
|
||||
foreach (headers_list() as $header) {
|
||||
if (stripos($header, 'content-type:') === 0) {
|
||||
// This handler only works with HTML and javascript outputs
|
||||
// text/javascript is obsolete in favour of application/javascript, but still used
|
||||
if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
|
||||
return 'js';
|
||||
} elseif (stripos($header, 'text/html') !== false) {
|
||||
return 'html';
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
private static function generateScript()
|
||||
{
|
||||
$script = array();
|
||||
|
@@ -17,6 +17,8 @@ use Monolog\Logger;
|
||||
/**
|
||||
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
|
||||
*
|
||||
* This also works out of the box with Firefox 43+
|
||||
*
|
||||
* @author Christophe Coevoet <stof@notk.org>
|
||||
*/
|
||||
class ChromePHPHandler extends AbstractProcessingHandler
|
||||
@@ -175,7 +177,8 @@ class ChromePHPHandler extends AbstractProcessingHandler
|
||||
return false;
|
||||
}
|
||||
|
||||
return preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']);
|
||||
// matches any Chrome, or Firefox 43+
|
||||
return preg_match('{\b(?:Chrome/\d+(?:\.\d+)*|Firefox/(?:4[3-9]|[5-9]\d|\d{3,})(?:\.\d)*)\b}', $_SERVER['HTTP_USER_AGENT']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace Monolog\Handler;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* Forwards records to multiple handlers
|
||||
*
|
||||
@@ -77,4 +79,16 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface
|
||||
$handler->handleBatch($records);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
foreach ($this->handlers as $handler) {
|
||||
$handler->setFormatter($formatter);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
104
src/Monolog/Handler/HandlerWrapper.php
Normal file
104
src/Monolog/Handler/HandlerWrapper.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?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\Formatter\FormatterInterface;
|
||||
|
||||
/**
|
||||
* This simple wrapper class can be used to extend handlers functionality.
|
||||
*
|
||||
* Example: A filtering handle. Inherit from this class, override isHandling() like this
|
||||
*
|
||||
* public function isHandling(array $record)
|
||||
* {
|
||||
* if ($record meets certain conditions) {
|
||||
* return false;
|
||||
* }
|
||||
* return $this->handler->isHandling($record);
|
||||
* }
|
||||
*
|
||||
* @author Alexey Karapetov <alexey@karapetov.com>
|
||||
*/
|
||||
class HandlerWrapper implements HandlerInterface
|
||||
{
|
||||
/**
|
||||
* @var HandlerInterface
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
/**
|
||||
* HandlerWrapper constructor.
|
||||
* @param HandlerInterface $handler
|
||||
*/
|
||||
public function __construct(HandlerInterface $handler)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function isHandling(array $record)
|
||||
{
|
||||
return $this->handler->isHandling($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handle(array $record)
|
||||
{
|
||||
return $this->handler->handle($record);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function handleBatch(array $records)
|
||||
{
|
||||
return $this->handler->handleBatch($records);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function pushProcessor($callback)
|
||||
{
|
||||
$this->handler->pushProcessor($callback);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function popProcessor()
|
||||
{
|
||||
return $this->handler->popProcessor();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setFormatter(FormatterInterface $formatter)
|
||||
{
|
||||
$this->handler->setFormatter($formatter);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getFormatter()
|
||||
{
|
||||
return $this->handler->getFormatter();
|
||||
}
|
||||
}
|
@@ -38,6 +38,12 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
Logger::EMERGENCY => Raven_Client::FATAL,
|
||||
);
|
||||
|
||||
/**
|
||||
* @var string should represent the current version of the calling
|
||||
* software. Can be any string (git commit, version number)
|
||||
*/
|
||||
private $release;
|
||||
|
||||
/**
|
||||
* @var Raven_Client the client object that sends the message to the server
|
||||
*/
|
||||
@@ -139,6 +145,10 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
$options['tags'] = array_merge($options['tags'], $record['context']['tags']);
|
||||
unset($record['context']['tags']);
|
||||
}
|
||||
if (!empty($record['context']['fingerprint'])) {
|
||||
$options['fingerprint'] = $record['context']['fingerprint'];
|
||||
unset($record['context']['fingerprint']);
|
||||
}
|
||||
if (!empty($record['context']['logger'])) {
|
||||
$options['logger'] = $record['context']['logger'];
|
||||
unset($record['context']['logger']);
|
||||
@@ -165,6 +175,10 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
$options['extra']['extra'] = $record['extra'];
|
||||
}
|
||||
|
||||
if (!empty($this->release) && !isset($options['release'])) {
|
||||
$options['release'] = $this->release;
|
||||
}
|
||||
|
||||
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
|
||||
$options['extra']['message'] = $record['formatted'];
|
||||
$this->ravenClient->captureException($record['context']['exception'], $options);
|
||||
@@ -204,4 +218,14 @@ class RavenHandler extends AbstractProcessingHandler
|
||||
{
|
||||
return array('checksum', 'release');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
*/
|
||||
public function setRelease($value)
|
||||
{
|
||||
$this->release = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
@@ -115,7 +115,11 @@ class RotatingFileHandler extends StreamHandler
|
||||
|
||||
foreach (array_slice($logFiles, $this->maxFiles) as $file) {
|
||||
if (is_writable($file)) {
|
||||
// suppress errors here as unlink() might fail if two processes
|
||||
// are cleaning up/rotating at the same time
|
||||
set_error_handler(function ($errno, $errstr, $errfile, $errline) {});
|
||||
unlink($file);
|
||||
restore_error_handler();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -157,6 +157,19 @@ class Logger implements LoggerInterface
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a new cloned instance with the name changed
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public function withName($name)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->name = $name;
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes a handler on to the stack.
|
||||
*
|
||||
|
@@ -75,4 +75,48 @@ class JsonFormatterTest extends TestCase
|
||||
});
|
||||
$this->assertEquals(implode("\n", $expected), $formatter->formatBatch($records));
|
||||
}
|
||||
|
||||
public function testDefFormatWithException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => $exception),
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$path = substr(json_encode($exception->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
} else {
|
||||
$path = substr(json_encode($exception->getFile()), 1, -1);
|
||||
}
|
||||
$this->assertEquals('{"level_name":"CRITICAL","channel":"core","context":{"exception":{"class":"RuntimeException","message":"'.$exception->getMessage().'","code":'.$exception->getCode().',"file":"'.$path.':'.$exception->getLine().'"}},"datetime":'.json_encode(new \DateTime()).',"extra":[],"message":"foobar"}'."\n", $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithPreviousException()
|
||||
{
|
||||
$formatter = new JsonFormatter();
|
||||
$exception = new \RuntimeException('Foo', 0, new \LogicException('Wut?'));
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'CRITICAL',
|
||||
'channel' => 'core',
|
||||
'context' => array('exception' => $exception),
|
||||
'datetime' => new \DateTime(),
|
||||
'extra' => array(),
|
||||
'message' => 'foobar',
|
||||
));
|
||||
|
||||
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
|
||||
$pathPrevious = substr(json_encode($exception->getPrevious()->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
$pathException = substr(json_encode($exception->getFile(), JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE), 1, -1);
|
||||
} else {
|
||||
$pathPrevious = substr(json_encode($exception->getPrevious()->getFile()), 1, -1);
|
||||
$pathException = substr(json_encode($exception->getFile()), 1, -1);
|
||||
}
|
||||
$this->assertEquals('{"level_name":"CRITICAL","channel":"core","context":{"exception":{"class":"RuntimeException","message":"'.$exception->getMessage().'","code":'.$exception->getCode().',"file":"'.$pathException.':'.$exception->getLine().'","previous":{"class":"LogicException","message":"'.$exception->getPrevious()->getMessage().'","code":'.$exception->getPrevious()->getCode().',"file":"'.$pathPrevious.':'.$exception->getPrevious()->getLine().'"}}},"datetime":'.json_encode(new \DateTime()).',"extra":[],"message":"foobar"}'."\n", $message);
|
||||
}
|
||||
}
|
||||
|
@@ -91,6 +91,20 @@ class LineFormatterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('['.date('Y-m-d').'] meh.ERROR: log '."\n", $message);
|
||||
}
|
||||
|
||||
public function testContextAndExtraReplacement()
|
||||
{
|
||||
$formatter = new LineFormatter('%context.foo% => %extra.foo%');
|
||||
$message = $formatter->format(array(
|
||||
'level_name' => 'ERROR',
|
||||
'channel' => 'meh',
|
||||
'context' => array('foo' => 'bar'),
|
||||
'datetime' => new \DateTime,
|
||||
'extra' => array('foo' => 'xbar'),
|
||||
'message' => 'log',
|
||||
));
|
||||
$this->assertEquals('bar => xbar', $message);
|
||||
}
|
||||
|
||||
public function testDefFormatWithObject()
|
||||
{
|
||||
$formatter = new LineFormatter(null, 'Y-m-d');
|
||||
|
130
tests/Monolog/Handler/HandlerWrapperTest.php
Normal file
130
tests/Monolog/Handler/HandlerWrapperTest.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @author Alexey Karapetov <alexey@karapetov.com>
|
||||
*/
|
||||
class HandlerWrapperTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @var HandlerWrapper
|
||||
*/
|
||||
private $wrapper;
|
||||
|
||||
private $handler;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
parent::setUp();
|
||||
$this->handler = $this->getMock('Monolog\\Handler\\HandlerInterface');
|
||||
$this->wrapper = new HandlerWrapper($this->handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function trueFalseDataProvider()
|
||||
{
|
||||
return array(
|
||||
array(true),
|
||||
array(false),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testIsHandling($result)
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$this->handler->expects($this->once())
|
||||
->method('isHandling')
|
||||
->with($record)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->isHandling($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testHandle($result)
|
||||
{
|
||||
$record = $this->getRecord();
|
||||
$this->handler->expects($this->once())
|
||||
->method('handle')
|
||||
->with($record)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->handle($record));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $result
|
||||
* @dataProvider trueFalseDataProvider
|
||||
*/
|
||||
public function testHandleBatch($result)
|
||||
{
|
||||
$records = $this->getMultipleRecords();
|
||||
$this->handler->expects($this->once())
|
||||
->method('handleBatch')
|
||||
->with($records)
|
||||
->willReturn($result);
|
||||
|
||||
$this->assertEquals($result, $this->wrapper->handleBatch($records));
|
||||
}
|
||||
|
||||
public function testPushProcessor()
|
||||
{
|
||||
$processor = function () {};
|
||||
$this->handler->expects($this->once())
|
||||
->method('pushProcessor')
|
||||
->with($processor);
|
||||
|
||||
$this->assertEquals($this->wrapper, $this->wrapper->pushProcessor($processor));
|
||||
}
|
||||
|
||||
public function testPopProcessor()
|
||||
{
|
||||
$processor = function () {};
|
||||
$this->handler->expects($this->once())
|
||||
->method('popProcessor')
|
||||
->willReturn($processor);
|
||||
|
||||
$this->assertEquals($processor, $this->wrapper->popProcessor());
|
||||
}
|
||||
|
||||
public function testSetFormatter()
|
||||
{
|
||||
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
|
||||
$this->handler->expects($this->once())
|
||||
->method('setFormatter')
|
||||
->with($formatter);
|
||||
|
||||
$this->assertEquals($this->wrapper, $this->wrapper->setFormatter($formatter));
|
||||
}
|
||||
|
||||
public function testGetFormatter()
|
||||
{
|
||||
$formatter = $this->getMock('Monolog\\Formatter\\FormatterInterface');
|
||||
$this->handler->expects($this->once())
|
||||
->method('getFormatter')
|
||||
->willReturn($formatter);
|
||||
|
||||
$this->assertEquals($formatter, $this->wrapper->getFormatter());
|
||||
}
|
||||
}
|
@@ -99,6 +99,18 @@ class RavenHandlerTest extends TestCase
|
||||
$this->assertEquals($release, $ravenClient->lastData['release']);
|
||||
}
|
||||
|
||||
public function testFingerprint()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
$handler = $this->getHandler($ravenClient);
|
||||
|
||||
$fingerprint = array('{{ default }}', 'other value');
|
||||
$record = $this->getRecord(Logger::INFO, 'test', array('fingerprint' => $fingerprint));
|
||||
$handler->handle($record);
|
||||
|
||||
$this->assertEquals($fingerprint, $ravenClient->lastData['fingerprint']);
|
||||
}
|
||||
|
||||
public function testUserContext()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
@@ -192,6 +204,22 @@ class RavenHandlerTest extends TestCase
|
||||
$this->assertSame($formatter, $handler->getBatchFormatter());
|
||||
}
|
||||
|
||||
public function testRelease()
|
||||
{
|
||||
$ravenClient = $this->getRavenClient();
|
||||
$handler = $this->getHandler($ravenClient);
|
||||
$release = 'v42.42.42';
|
||||
$handler->setRelease($release);
|
||||
$record = $this->getRecord(Logger::INFO, 'test');
|
||||
$handler->handle($record);
|
||||
$this->assertEquals($release, $ravenClient->lastData['release']);
|
||||
|
||||
$localRelease = 'v41.41.41';
|
||||
$record = $this->getRecord(Logger::INFO, 'test', array('release' => $localRelease));
|
||||
$handler->handle($record);
|
||||
$this->assertEquals($localRelease, $ravenClient->lastData['release']);
|
||||
}
|
||||
|
||||
private function methodThatThrowsAnException()
|
||||
{
|
||||
throw new \Exception('This is an exception');
|
||||
|
@@ -33,6 +33,19 @@ class LoggerTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertEquals('ERROR', Logger::getLevelName(Logger::ERROR));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::withName
|
||||
*/
|
||||
public function testWithName()
|
||||
{
|
||||
$first = new Logger('first', array($handler = new TestHandler()));
|
||||
$second = $first->withName('second');
|
||||
|
||||
$this->assertSame('first', $first->getName());
|
||||
$this->assertSame('second', $second->getName());
|
||||
$this->assertSame($handler, $second->popHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers Monolog\Logger::toMonologLevel
|
||||
*/
|
||||
|
Reference in New Issue
Block a user