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

Skip to content

Commit f1c01ed

Browse files
committed
feature #15521 [Debug] Add BufferingLogger for errors that happen before a proper logger is configured (nicolas-grekas)
This PR was merged into the 2.8 branch. Discussion ---------- [Debug] Add BufferingLogger for errors that happen before a proper logger is configured | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | BC breaks? | no | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - This allows catching e.g. deprecations that happen during bootstrapping. Commits ------- 2a9647d [Debug] Add BufferingLogger for errors that happen before a proper logger is configured
2 parents 0383559 + 2a9647d commit f1c01ed

File tree

5 files changed

+119
-5
lines changed

5 files changed

+119
-5
lines changed
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
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+
16+
/**
17+
* A buffering logger that stacks logs for later.
18+
*
19+
* @author Nicolas Grekas <[email protected]>
20+
*/
21+
class BufferingLogger extends AbstractLogger
22+
{
23+
private $logs = array();
24+
25+
public function log($level, $message, array $context = array())
26+
{
27+
$this->logs[] = array($level, $message, $context);
28+
}
29+
30+
public function cleanLogs()
31+
{
32+
$logs = $this->logs;
33+
$this->logs = array();
34+
35+
return $logs;
36+
}
37+
}

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 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: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,10 @@ public static function enable($errorReportingLevel = null, $displayErrors = true
5252
// CLI - display errors only if they're not already logged to STDERR
5353
ini_set('display_errors', 1);
5454
}
55-
$handler = ErrorHandler::register();
56-
if (!$displayErrors) {
57-
$handler->throwAt(0, true);
55+
if ($displayErrors) {
56+
ErrorHandler::register(new ErrorHandler(new BufferingLogger()))->screamAt(E_DEPRECATED | E_USER_DEPRECATED);
57+
} else {
58+
ErrorHandler::register()->throwAt(0, true);
5859
}
5960

6061
DebugClassLoader::enable();

src/Symfony/Component/Debug/ErrorHandler.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ class ErrorHandler
9696
private $loggedTraces = array();
9797
private $isRecursive = 0;
9898
private $exceptionHandler;
99+
private $bootstrappingLogger;
99100

100101
private static $reservedMemory;
101102
private static $stackedErrors = array();
@@ -152,6 +153,14 @@ public static function register($handler = null, $replace = true)
152153
return $handler;
153154
}
154155

156+
public function __construct(BufferingLogger $bootstrappingLogger = null)
157+
{
158+
if ($bootstrappingLogger) {
159+
$this->bootstrappingLogger = $bootstrappingLogger;
160+
$this->setDefaultLogger($bootstrappingLogger);
161+
}
162+
}
163+
155164
/**
156165
* Sets a logger to non assigned errors levels.
157166
*
@@ -165,7 +174,7 @@ public function setDefaultLogger(LoggerInterface $logger, $levels = null, $repla
165174

166175
if (is_array($levels)) {
167176
foreach ($levels as $type => $logLevel) {
168-
if (empty($this->loggers[$type][0]) || $replace) {
177+
if (empty($this->loggers[$type][0]) || $replace || $this->loggers[$type][0] === $this->bootstrappingLogger) {
169178
$loggers[$type] = array($logger, $logLevel);
170179
}
171180
}
@@ -174,7 +183,7 @@ public function setDefaultLogger(LoggerInterface $logger, $levels = null, $repla
174183
$levels = E_ALL | E_STRICT;
175184
}
176185
foreach ($this->loggers as $type => $log) {
177-
if (($type & $levels) && (empty($log[0]) || $replace)) {
186+
if (($type & $levels) && (empty($log[0]) || $replace || $log[0] === $this->bootstrappingLogger)) {
178187
$log[0] = $logger;
179188
$loggers[$type] = $log;
180189
}
@@ -197,6 +206,7 @@ public function setLoggers(array $loggers)
197206
{
198207
$prevLogged = $this->loggedErrors;
199208
$prev = $this->loggers;
209+
$flush = array();
200210

201211
foreach ($loggers as $type => $log) {
202212
if (!isset($prev[$type])) {
@@ -215,9 +225,24 @@ public function setLoggers(array $loggers)
215225
throw new \InvalidArgumentException('Invalid logger provided');
216226
}
217227
$this->loggers[$type] = $log + $prev[$type];
228+
229+
if ($this->bootstrappingLogger && $prev[$type][0] === $this->bootstrappingLogger) {
230+
$flush[$type] = $type;
231+
}
218232
}
219233
$this->reRegister($prevLogged | $this->thrownErrors);
220234

235+
if ($flush) {
236+
foreach ($this->bootstrappingLogger->cleanLogs() as $log) {
237+
$type = $log[2]['type'];
238+
if (!isset($flush[$type])) {
239+
$this->bootstrappingLogger->log($log[0], $log[1], $log[2]);
240+
} elseif ($this->loggers[$type][0]) {
241+
$this->loggers[$type][0]->log($this->loggers[$type][1], $log[1], $log[2]);
242+
}
243+
}
244+
}
245+
221246
return $prev;
222247
}
223248

src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Psr\Log\LogLevel;
1515
use Symfony\Component\Debug\ErrorHandler;
16+
use Symfony\Component\Debug\BufferingLogger;
1617
use Symfony\Component\Debug\Exception\ContextErrorException;
1718

1819
/**
@@ -399,6 +400,49 @@ public function testErrorStacking()
399400
}
400401
}
401402

403+
public function testBootstrappingLogger()
404+
{
405+
$bootLogger = new BufferingLogger();
406+
$handler = new ErrorHandler($bootLogger);
407+
408+
$loggers = array(
409+
E_DEPRECATED => array($bootLogger, LogLevel::INFO),
410+
E_USER_DEPRECATED => array($bootLogger, LogLevel::INFO),
411+
E_NOTICE => array($bootLogger, LogLevel::WARNING),
412+
E_USER_NOTICE => array($bootLogger, LogLevel::WARNING),
413+
E_STRICT => array($bootLogger, LogLevel::WARNING),
414+
E_WARNING => array($bootLogger, LogLevel::WARNING),
415+
E_USER_WARNING => array($bootLogger, LogLevel::WARNING),
416+
E_COMPILE_WARNING => array($bootLogger, LogLevel::WARNING),
417+
E_CORE_WARNING => array($bootLogger, LogLevel::WARNING),
418+
E_USER_ERROR => array($bootLogger, LogLevel::CRITICAL),
419+
E_RECOVERABLE_ERROR => array($bootLogger, LogLevel::CRITICAL),
420+
E_COMPILE_ERROR => array($bootLogger, LogLevel::CRITICAL),
421+
E_PARSE => array($bootLogger, LogLevel::CRITICAL),
422+
E_ERROR => array($bootLogger, LogLevel::CRITICAL),
423+
E_CORE_ERROR => array($bootLogger, LogLevel::CRITICAL),
424+
);
425+
426+
$this->assertSame($loggers, $handler->setLoggers(array()));
427+
428+
$handler->handleError(E_DEPRECATED, 'Foo message', __FILE__, 123, array());
429+
$expectedLog = array(LogLevel::INFO, 'Foo message', array('type' => E_DEPRECATED, 'file' => __FILE__, 'line' => 123, 'level' => error_reporting()));
430+
431+
$logs = $bootLogger->cleanLogs();
432+
unset($logs[0][2]['stack']);
433+
434+
$this->assertSame(array($expectedLog), $logs);
435+
436+
$bootLogger->log($expectedLog[0], $expectedLog[1], $expectedLog[2]);
437+
438+
$mockLogger = $this->getMock('Psr\Log\LoggerInterface');
439+
$mockLogger->expects($this->once())
440+
->method('log')
441+
->with(LogLevel::WARNING, 'Foo message', $expectedLog[2]);
442+
443+
$handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING)));
444+
}
445+
402446
public function testHandleFatalError()
403447
{
404448
try {

0 commit comments

Comments
 (0)