1
0
mirror of https://github.com/Seldaek/monolog.git synced 2025-10-23 17:46:09 +02:00

Merge branch '1.x'

This commit is contained in:
Jordi Boggiano
2018-11-04 18:40:32 +01:00
27 changed files with 654 additions and 24 deletions

View File

@@ -13,6 +13,7 @@ namespace Monolog;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Monolog\Registry;
/**
* Monolog error handler
@@ -163,7 +164,7 @@ class ErrorHandler
$this->logger->log(
$level,
sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()),
sprintf('Uncaught Exception %s: "%s" at %s line %s', Utils::getClass($e), $e->getMessage(), $e->getFile(), $e->getLine()),
['exception' => $e]
);

View File

@@ -11,6 +11,7 @@
namespace Monolog\Formatter;
use Monolog\Utils;
use Throwable;
/**
@@ -166,7 +167,7 @@ class JsonFormatter extends NormalizerFormatter
protected function normalizeException(Throwable $e, int $depth = 0): array
{
$data = [
'class' => get_class($e),
'class' => Utils::getClass($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile().':'.$e->getLine(),

View File

@@ -11,6 +11,8 @@
namespace Monolog\Formatter;
use Monolog\Utils;
/**
* Formats incoming records into a one-line string
*
@@ -168,7 +170,7 @@ class LineFormatter extends NormalizerFormatter
private function formatException(\Throwable $e): string
{
$str = '[object] (' . get_class($e) . '(code: ' . $e->getCode() . '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')';
$str = '[object] (' . Utils::getClass($e) . '(code: ' . $e->getCode() . '): ' . $e->getMessage() . ' at ' . $e->getFile() . ':' . $e->getLine() . ')';
if ($this->includeStacktraces) {
$str .= "\n[stacktrace]\n" . $e->getTraceAsString() . "\n";
}

View File

@@ -12,6 +12,7 @@
namespace Monolog\Formatter;
use MongoDB\BSON\UTCDateTime;
use Monolog\Utils;
/**
* Formats a record for use with the MongoDBHandler.
@@ -83,7 +84,7 @@ class MongoDBFormatter implements FormatterInterface
protected function formatObject($value, int $nestingLevel)
{
$objectVars = get_object_vars($value);
$objectVars['class'] = get_class($value);
$objectVars['class'] = Utils::getClass($value);
return $this->formatArray($objectVars, $nestingLevel);
}
@@ -91,7 +92,7 @@ class MongoDBFormatter implements FormatterInterface
protected function formatException(\Throwable $exception, int $nestingLevel)
{
$formattedException = [
'class' => get_class($exception),
'class' => Utils::getClass($exception),
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'file' => $exception->getFile() . ':' . $exception->getLine(),

View File

@@ -13,6 +13,7 @@ namespace Monolog\Formatter;
use Throwable;
use Monolog\DateTimeImmutable;
use Monolog\Utils;
/**
* Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
@@ -146,7 +147,7 @@ class NormalizerFormatter implements FormatterInterface
}
}
return [get_class($data) => $value];
return [Utils::getClass($data) => $value];
}
if (is_resource($data)) {
@@ -162,7 +163,7 @@ class NormalizerFormatter implements FormatterInterface
protected function normalizeException(Throwable $e, int $depth = 0)
{
$data = [
'class' => get_class($e),
'class' => Utils::getClass($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile().':'.$e->getLine(),
@@ -195,7 +196,7 @@ class NormalizerFormatter implements FormatterInterface
// as a class name to avoid any unexpected leak of sensitive information
$frame['args'] = array_map(function ($arg) {
if (is_object($arg) && !$arg instanceof \DateTimeInterface) {
return sprintf("[object] (%s)", get_class($arg));
return sprintf("[object] (%s)", Utils::getClass($arg));
}
return $arg;

View File

@@ -11,6 +11,8 @@
namespace Monolog\Handler;
use Monolog\ResettableInterface;
/**
* Base Handler class providing the Handler structure
*
@@ -19,7 +21,7 @@ namespace Monolog\Handler;
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface
abstract class AbstractProcessingHandler extends AbstractHandler implements ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface
{
use ProcessableHandlerTrait;
use FormattableHandlerTrait;
@@ -48,4 +50,15 @@ abstract class AbstractProcessingHandler extends AbstractHandler implements Proc
* Writes the record down to the log of the implementing handler
*/
abstract protected function write(array $record): void;
public function reset()
{
$this->close();
foreach ($this->processors as $processor) {
if ($processor instanceof ResettableInterface) {
$processor->reset();
}
}
}
}

View File

@@ -70,14 +70,19 @@ class BrowserConsoleHandler extends AbstractProcessingHandler
} elseif ($format === 'js') {
static::writeOutput(static::generateScript());
}
static::reset();
static::resetStatic();
}
}
public function reset()
{
self::resetStatic();
}
/**
* Forget all logged records
*/
public static function reset(): void
public static function resetStatic(): void
{
static::$records = [];
}

View File

@@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\ResettableInterface;
/**
* Buffers all records until closing the handler and then pass them as batch.
@@ -114,4 +115,13 @@ class BufferHandler extends AbstractHandler implements ProcessableHandlerInterfa
$this->bufferSize = 0;
$this->buffer = [];
}
public function reset()
{
parent::reset();
if ($this->handler instanceof ResettableInterface) {
$this->handler->reset();
}
}
}

View File

@@ -14,6 +14,7 @@ namespace Monolog\Handler;
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
use Monolog\Logger;
use Monolog\ResettableInterface;
/**
* Buffers all records until a certain level is reached
@@ -147,7 +148,14 @@ class FingersCrossedHandler extends Handler implements ProcessableHandlerInterfa
*/
public function reset()
{
parent::reset();
$this->buffer = array();
$this->buffering = true;
if ($this->handler instanceof ResettableInterface) {
$this->handler->reset();
}
}
/**

View File

@@ -12,6 +12,7 @@
namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\ResettableInterface;
/**
* Forwards records to multiple handlers
@@ -90,6 +91,17 @@ class GroupHandler extends Handler implements ProcessableHandlerInterface
}
}
public function reset()
{
parent::reset();
foreach ($this->handlers as $handler) {
if ($handler instanceof ResettableInterface) {
$handler->reset();
}
}
}
/**
* {@inheritdoc}
*/

View File

@@ -11,6 +11,7 @@
namespace Monolog\Handler;
use Monolog\ResettableInterface;
use Monolog\Formatter\FormatterInterface;
/**
@@ -30,7 +31,7 @@ use Monolog\Formatter\FormatterInterface;
*
* @author Alexey Karapetov <alexey@karapetov.com>
*/
class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface
class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, FormattableHandlerInterface, ResettableInterface
{
/**
* @var HandlerInterface
@@ -127,4 +128,11 @@ class HandlerWrapper implements HandlerInterface, ProcessableHandlerInterface, F
throw new \LogicException('The wrapped handler does not implement ' . FormattableHandlerInterface::class);
}
public function reset()
{
if ($this->handler instanceof ResettableInterface) {
return $this->handler->reset();
}
}
}

View File

@@ -18,7 +18,7 @@ use Raven_Client;
/**
* Handler to send messages to a Sentry (https://github.com/getsentry/sentry) server
* using raven-php (https://github.com/getsentry/raven-php)
* using sentry-php (https://github.com/getsentry/sentry-php)
*
* @author Marc Abramowitz <marc@marc-abramowitz.com>
*/

View File

@@ -25,7 +25,7 @@ use Throwable;
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class Logger implements LoggerInterface
class Logger implements LoggerInterface, ResettableInterface
{
/**
* Detailed debug information
@@ -333,6 +333,21 @@ class Logger implements LoggerInterface
return true;
}
public function reset()
{
foreach ($this->handlers as $handler) {
if ($handler instanceof ResettableInterface) {
$handler->reset();
}
}
foreach ($this->processors as $processor) {
if ($processor instanceof ResettableInterface) {
$processor->reset();
}
}
}
/**
* Gets all supported logging levels.
*

View File

@@ -11,6 +11,8 @@
namespace Monolog\Processor;
use Monolog\Utils;
/**
* Processes a record's message according to PSR-3 rules
*
@@ -66,7 +68,7 @@ class PsrLogMessageProcessor implements ProcessorInterface
$replacements[$placeholder] = $val->format($this->dateFormat ?: static::SIMPLE_DATE);
}
} elseif (is_object($val)) {
$replacements[$placeholder] = '[object '.get_class($val).']';
$replacements[$placeholder] = '[object '.Utils::getClass($val).']';
} elseif (is_array($val)) {
$replacements[$placeholder] = 'array'.@json_encode($val);
} else {

View File

@@ -11,12 +11,14 @@
namespace Monolog\Processor;
use Monolog\ResettableInterface;
/**
* Adds a unique identifier into records
*
* @author Simon Mönch <sm@webfactory.de>
*/
class UidProcessor implements ProcessorInterface
class UidProcessor implements ProcessorInterface, ResettableInterface
{
private $uid;
@@ -26,7 +28,7 @@ class UidProcessor implements ProcessorInterface
throw new \InvalidArgumentException('The uid length must be an integer between 1 and 32');
}
$this->uid = substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length);
$this->uid = $this->generateUid($length);
}
public function __invoke(array $record): array
@@ -43,4 +45,14 @@ class UidProcessor implements ProcessorInterface
{
return $this->uid;
}
public function reset()
{
$this->uid = $this->generateUid(strlen($this->uid));
}
private function generateUid($length)
{
return substr(bin2hex(random_bytes((int) ceil($length / 2))), 0, $length);
}
}

View File

@@ -130,4 +130,14 @@ class Registry
{
return self::getInstance($name);
}
/**
* @internal
*/
public function getClass($object)
{
$class = \get_class($object);
return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
}
}

View File

@@ -0,0 +1,25 @@
<?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 or Processor implementing this interface will be reset when Logger::reset() is called.
*
* Resetting an Handler or a Processor usually means cleaning all buffers or
* resetting in its internal state. This should also generally close() the handler.
*
* @author Grégoire Pineau <lyrixx@lyrixx.info>
*/
interface ResettableInterface
{
public function reset();
}

View File

@@ -0,0 +1,115 @@
<?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;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use ReflectionExtension;
/**
* Monolog POSIX signal handler
*
* @author Robert Gust-Bardon <robert@gust-bardon.org>
*/
class SignalHandler
{
private $logger;
private $previousSignalHandler = array();
private $signalLevelMap = array();
private $signalRestartSyscalls = array();
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
public function registerSignalHandler($signo, $level = LogLevel::CRITICAL, $callPrevious = true, $restartSyscalls = true, $async = true)
{
if (!extension_loaded('pcntl') || !function_exists('pcntl_signal')) {
return $this;
}
if ($callPrevious) {
if (function_exists('pcntl_signal_get_handler')) {
$handler = pcntl_signal_get_handler($signo);
if ($handler === false) {
return $this;
}
$this->previousSignalHandler[$signo] = $handler;
} else {
$this->previousSignalHandler[$signo] = true;
}
} else {
unset($this->previousSignalHandler[$signo]);
}
$this->signalLevelMap[$signo] = $level;
$this->signalRestartSyscalls[$signo] = $restartSyscalls;
if (function_exists('pcntl_async_signals') && $async !== null) {
pcntl_async_signals($async);
}
pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
return $this;
}
public function handleSignal($signo, array $siginfo = null)
{
static $signals = array();
if (!$signals && extension_loaded('pcntl')) {
$pcntl = new ReflectionExtension('pcntl');
$constants = $pcntl->getConstants();
if (!$constants) {
// HHVM 3.24.2 returns an empty array.
$constants = get_defined_constants(true);
$constants = $constants['Core'];
}
foreach ($constants as $name => $value) {
if (substr($name, 0, 3) === 'SIG' && $name[3] !== '_' && is_int($value)) {
$signals[$value] = $name;
}
}
unset($constants);
}
$level = isset($this->signalLevelMap[$signo]) ? $this->signalLevelMap[$signo] : LogLevel::CRITICAL;
$signal = isset($signals[$signo]) ? $signals[$signo] : $signo;
$context = isset($siginfo) ? $siginfo : array();
$this->logger->log($level, sprintf('Program received signal %s', $signal), $context);
if (!isset($this->previousSignalHandler[$signo])) {
return;
}
if ($this->previousSignalHandler[$signo] === true || $this->previousSignalHandler[$signo] === SIG_DFL) {
if (extension_loaded('pcntl') && function_exists('pcntl_signal') && function_exists('pcntl_sigprocmask') && function_exists('pcntl_signal_dispatch')
&& extension_loaded('posix') && function_exists('posix_getpid') && function_exists('posix_kill')) {
$restartSyscalls = isset($this->restartSyscalls[$signo]) ? $this->restartSyscalls[$signo] : true;
pcntl_signal($signo, SIG_DFL, $restartSyscalls);
pcntl_sigprocmask(SIG_UNBLOCK, array($signo), $oldset);
posix_kill(posix_getpid(), $signo);
pcntl_signal_dispatch();
pcntl_sigprocmask(SIG_SETMASK, $oldset);
pcntl_signal($signo, array($this, 'handleSignal'), $restartSyscalls);
}
} elseif (is_callable($this->previousSignalHandler[$signo])) {
if (PHP_VERSION_ID >= 70100) {
$this->previousSignalHandler[$signo]($signo, $siginfo);
} else {
$this->previousSignalHandler[$signo]($signo);
}
}
}
}

25
src/Monolog/Utils.php Normal file
View File

@@ -0,0 +1,25 @@
<?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;
class Utils
{
/**
* @internal
*/
public function getClass($object)
{
$class = \get_class($object);
return 'c' === $class[0] && 0 === strpos($class, "class@anonymous\0") ? get_parent_class($class).'@anonymous' : $class;
}
}