Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c2e5ba8

Browse files
[Debug] Add BootstrappingLogger to buffer errors that happen before a proper logger is configured
1 parent 7f745d7 commit c2e5ba8

File tree

6 files changed

+196
-4
lines changed

6 files changed

+196
-4
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Debug;
13+
14+
use Psr\Log\LoggerInterface;
15+
16+
/**
17+
* A bootstrapping logger that can stack logs and flush them when required to another logger.
18+
*
19+
* @author Nicolas Grekas <[email protected]>
20+
*/
21+
interface BootstrappingLoggerInterface extends LoggerInterface
22+
{
23+
public function flush(LoggerInterface $logger);
24+
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Debug;
13+
14+
use Psr\Log\AbstractLogger;
15+
use Psr\Log\LoggerInterface;
16+
17+
/**
18+
* A buffering logger that stacks logs and flushes them when required to another logger.
19+
*
20+
* @author Nicolas Grekas <[email protected]>
21+
*/
22+
class BufferingLogger extends AbstractLogger implements BootstrappingLoggerInterface
23+
{
24+
private $stripScopeVars;
25+
private $logs = array();
26+
27+
public function __construct($stripScopeVars = true)
28+
{
29+
$this->stripScopeVars = $stripScopeVars;
30+
}
31+
32+
public function log($level, $message, array $context = array())
33+
{
34+
if ($this->stripScopeVars) {
35+
if (isset($context['stack']) && is_array($context['stack'])) {
36+
foreach ($context['stack'] as &$frame) {
37+
unset($frame['args'], $frame['object'], $frame);
38+
}
39+
}
40+
unset($context['scope_vars']);
41+
}
42+
43+
$this->logs[] = array($level, $message, $context);
44+
}
45+
46+
public function flush(LoggerInterface $logger)
47+
{
48+
$logs = $this->logs;
49+
$this->logs = array();
50+
51+
foreach ($logs as $log) {
52+
$logger->log($log[0], $log[1], $log[2]);
53+
}
54+
}
55+
}

src/Symfony/Component/Debug/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
CHANGELOG
22
=========
33

4+
2.8.0
5+
-----
6+
7+
* added BufferingLogger and BootstrappingLoggerInterface for errors that happen before a proper logger is configured
8+
* allow throwing from `__toString()` with `return trigger_error($e, E_USER_ERROR);`
9+
* deprecate ExceptionHandler::createResponse
10+
411
2.7.0
512
-----
613

src/Symfony/Component/Debug/Debug.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,12 @@ public static function enable($errorReportingLevel = null, $displayErrors = true
5353
ini_set('display_errors', 1);
5454
}
5555
$handler = ErrorHandler::register();
56+
$loggers = $handler->setLoggers(array());
57+
foreach ($loggers as &$level) {
58+
$level[0] = new BufferingLogger();
59+
}
60+
unset($level);
61+
$handler->setLoggers($loggers);
5662
if (!$displayErrors) {
5763
$handler->throwAt(0, true);
5864
}

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,7 @@ public function setDefaultLogger(LoggerInterface $logger, $levels = null, $repla
165165

166166
if (is_array($levels)) {
167167
foreach ($levels as $type => $logLevel) {
168-
if (empty($this->loggers[$type][0]) || $replace) {
168+
if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] instanceof BootstrappingLoggerInterface) {
169169
$loggers[$type] = array($logger, $logLevel);
170170
}
171171
}
@@ -174,7 +174,7 @@ public function setDefaultLogger(LoggerInterface $logger, $levels = null, $repla
174174
$levels = E_ALL | E_STRICT;
175175
}
176176
foreach ($this->loggers as $type => $log) {
177-
if (($type & $levels) && (empty($log[0]) || $replace)) {
177+
if (($type & $levels) && (empty($log[0]) || $replace || $log[0] instanceof BootstrappingLoggerInterface)) {
178178
$log[0] = $logger;
179179
$loggers[$type] = $log;
180180
}
@@ -215,6 +215,10 @@ public function setLoggers(array $loggers)
215215
throw new \InvalidArgumentException('Invalid logger provided');
216216
}
217217
$this->loggers[$type] = $log + $prev[$type];
218+
219+
if (($this->loggedErrors & $type) && $prev[$type][0] instanceof BootstrappingLoggerInterface) {
220+
$prev[$type][0]->flush($this->loggers[$type][0]);
221+
}
218222
}
219223
$this->reRegister($prevLogged | $this->thrownErrors);
220224

@@ -252,7 +256,7 @@ public function setExceptionHandler($handler)
252256
public function throwAt($levels, $replace = false)
253257
{
254258
$prev = $this->thrownErrors;
255-
$this->thrownErrors = ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
259+
$this->thrownErrors = (E_ALL | E_STRICT) & ($levels | E_RECOVERABLE_ERROR | E_USER_ERROR) & ~E_USER_DEPRECATED & ~E_DEPRECATED;
256260
if (!$replace) {
257261
$this->thrownErrors |= $prev;
258262
}
@@ -490,7 +494,7 @@ public function handleError($type, $message, $file, $line, array $context, array
490494
}
491495

492496
/**
493-
* Handles an exception by logging then forwarding it to an other handler.
497+
* Handles an exception by logging then forwarding it to another handler.
494498
*
495499
* @param \Exception|\Throwable $exception An exception to handle
496500
* @param array $error An array as returned by error_get_last()
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Debug\Tests;
13+
14+
use Psr\Log\LogLevel;
15+
use Symfony\Component\Debug\BufferingLogger;
16+
use Symfony\Component\Debug\ErrorHandler;
17+
18+
/**
19+
* BufferingLoggerTest.
20+
*
21+
* @author Nicolas Grekas <[email protected]>
22+
*/
23+
class BufferingLoggerTest extends \PHPUnit_Framework_TestCase
24+
{
25+
public function testFlush()
26+
{
27+
for ($strip = 0; $strip < 2; ++$strip) {
28+
$logger = new BufferingLogger((bool) $strip);
29+
30+
$context = array(
31+
'level' => 0,
32+
'type' => E_USER_NOTICE,
33+
'file' => __FILE__,
34+
'line' => 123,
35+
'scope_vars' => 234,
36+
'stack' => array(
37+
array(
38+
'file' => __FILE__,
39+
'args' => 345,
40+
'object' => 456,
41+
),
42+
),
43+
);
44+
45+
$logger->log(LogLevel::INFO, 'Foo message', $context);
46+
47+
if ($strip) {
48+
unset($context['scope_vars'], $context['stack'][0]['args'], $context['stack'][0]['object']);
49+
}
50+
51+
$mockLogger = $this->getMock('Psr\Log\LoggerInterface');
52+
$mockLogger->expects($this->once())
53+
->method('log')
54+
->with(LogLevel::INFO, 'Foo message', $context);
55+
56+
$logger->flush($mockLogger);
57+
}
58+
}
59+
60+
public function testLifecycle()
61+
{
62+
$logger = new BufferingLogger();
63+
64+
$handler = new ErrorHandler();
65+
$handler->setDefaultLogger($logger);
66+
67+
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
68+
69+
$mockLogger = $this->getMock('Psr\Log\LoggerInterface');
70+
$mockLogger->expects($this->once())
71+
->method('log')
72+
->with(LogLevel::INFO, 'Foo message', $this->isType('array'));
73+
74+
$handler->setDefaultLogger($mockLogger);
75+
76+
$loggers = array(
77+
E_DEPRECATED => array($mockLogger, LogLevel::INFO),
78+
E_USER_DEPRECATED => array($mockLogger, LogLevel::INFO),
79+
E_NOTICE => array($mockLogger, LogLevel::WARNING),
80+
E_USER_NOTICE => array($mockLogger, LogLevel::WARNING),
81+
E_STRICT => array($mockLogger, LogLevel::WARNING),
82+
E_WARNING => array($mockLogger, LogLevel::WARNING),
83+
E_USER_WARNING => array($mockLogger, LogLevel::WARNING),
84+
E_COMPILE_WARNING => array($mockLogger, LogLevel::WARNING),
85+
E_CORE_WARNING => array($mockLogger, LogLevel::WARNING),
86+
E_USER_ERROR => array($mockLogger, LogLevel::CRITICAL),
87+
E_RECOVERABLE_ERROR => array($mockLogger, LogLevel::CRITICAL),
88+
E_COMPILE_ERROR => array($mockLogger, LogLevel::CRITICAL),
89+
E_PARSE => array($mockLogger, LogLevel::CRITICAL),
90+
E_ERROR => array($mockLogger, LogLevel::CRITICAL),
91+
E_CORE_ERROR => array($mockLogger, LogLevel::CRITICAL),
92+
);
93+
94+
$this->assertSame($loggers, $handler->setLoggers(array()));
95+
}
96+
}

0 commit comments

Comments
 (0)