Skip to content

Commit db1fa17

Browse files
committed
Make logger implement DebugLoggerInterface
1 parent 1198986 commit db1fa17

File tree

3 files changed

+134
-2
lines changed

3 files changed

+134
-2
lines changed

src/Symfony/Component/HttpKernel/DependencyInjection/LoggerPass.php

+19-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,11 @@
1414
use Psr\Log\LoggerInterface;
1515
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
1616
use Symfony\Component\DependencyInjection\ContainerBuilder;
17+
use Symfony\Component\DependencyInjection\Definition;
18+
use Symfony\Component\DependencyInjection\Reference;
19+
use Symfony\Component\HttpFoundation\RequestStack;
1720
use Symfony\Component\HttpKernel\Log\Logger;
21+
use Symfony\Component\HttpKernel\Log\Recorder;
1822

1923
/**
2024
* Registers the default logger if necessary.
@@ -32,7 +36,21 @@ public function process(ContainerBuilder $container)
3236
return;
3337
}
3438

39+
$recorder = null;
40+
if ($container->getParameter('kernel.debug')) {
41+
$recorder = new Definition(Recorder::class, ['$requestStack' => new Reference(RequestStack::class)]);
42+
}
43+
3544
$container->register('logger', Logger::class)
36-
->setPublic(false);
45+
->setPublic(false)
46+
->addMethodCall('setRecorder', [$recorder])
47+
->setConfigurator([__CLASS__, 'configureLogger']);
48+
}
49+
50+
public static function configureLogger(mixed $logger)
51+
{
52+
if (\is_object($logger) && method_exists($logger, 'setRecorder') && \in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) {
53+
$logger->setRecorder(null);
54+
}
3755
}
3856
}

src/Symfony/Component/HttpKernel/Log/Logger.php

+29-1
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
use Psr\Log\AbstractLogger;
1515
use Psr\Log\InvalidArgumentException;
1616
use Psr\Log\LogLevel;
17+
use Symfony\Component\HttpFoundation\Request;
1718

1819
/**
1920
* Minimalist PSR-3 logger designed to write in stderr or any other stream.
2021
*
2122
* @author Kévin Dunglas <dunglas@gmail.com>
2223
*/
23-
class Logger extends AbstractLogger
24+
class Logger extends AbstractLogger implements DebugLoggerInterface
2425
{
2526
private const LEVELS = [
2627
LogLevel::DEBUG => 0,
@@ -39,6 +40,9 @@ class Logger extends AbstractLogger
3940
/** @var resource|null */
4041
private $handle;
4142

43+
/** @var Recorder|null */
44+
private $recorder;
45+
4246
/**
4347
* @param string|resource|null $output
4448
*/
@@ -69,6 +73,11 @@ public function __construct(string $minLevel = null, $output = null, callable $f
6973
}
7074
}
7175

76+
public function setRecorder(?Recorder $recorder): void
77+
{
78+
$this->recorder = $recorder;
79+
}
80+
7281
public function log($level, $message, array $context = []): void
7382
{
7483
if (!isset(self::LEVELS[$level])) {
@@ -85,6 +94,25 @@ public function log($level, $message, array $context = []): void
8594
} else {
8695
error_log($formatter($level, $message, $context, false));
8796
}
97+
98+
if ($this->recorder) {
99+
$this->recorder->record($level, $message, $context);
100+
}
101+
}
102+
103+
public function getLogs(Request $request = null)
104+
{
105+
return $this->recorder?->getLogs($request) ?? [];
106+
}
107+
108+
public function countErrors(Request $request = null)
109+
{
110+
return $this->recorder?->countErrors($request) ?? 0;
111+
}
112+
113+
public function clear()
114+
{
115+
$this->recorder?->clear();
88116
}
89117

90118
private function format(string $level, string $message, array $context, bool $prefixDate = true): string
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
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\HttpKernel\Log;
13+
14+
use Psr\Log\LogLevel;
15+
use Symfony\Component\HttpFoundation\Request;
16+
use Symfony\Component\HttpFoundation\RequestStack;
17+
18+
class Recorder implements DebugLoggerInterface
19+
{
20+
private const PRIORITIES = [
21+
LogLevel::DEBUG => 100,
22+
LogLevel::INFO => 200,
23+
LogLevel::NOTICE => 250,
24+
LogLevel::WARNING => 300,
25+
LogLevel::ERROR => 400,
26+
LogLevel::CRITICAL => 500,
27+
LogLevel::ALERT => 550,
28+
LogLevel::EMERGENCY => 600,
29+
];
30+
31+
private array $logs = [];
32+
private array $errorCount = [];
33+
34+
public function __construct(private readonly RequestStack $requestStack)
35+
{
36+
}
37+
38+
public function record($level, $message, array $context): void
39+
{
40+
$request = $this->requestStack->getCurrentRequest();
41+
$hash = $request ? spl_object_hash($request) : '';
42+
43+
$this->logs[$hash][] = [
44+
'channel' => null,
45+
'context' => $context,
46+
'message' => $message,
47+
'priority' => self::PRIORITIES[$level],
48+
'priorityName' => $level,
49+
'timestamp' => time(),
50+
'timestamp_rfc3339' => date(\DATE_RFC3339_EXTENDED),
51+
];
52+
53+
$this->errorCount[$hash] ??= 0;
54+
switch ($level) {
55+
case LogLevel::ERROR:
56+
case LogLevel::CRITICAL:
57+
case LogLevel::ALERT:
58+
case LogLevel::EMERGENCY:
59+
++$this->errorCount[$hash];
60+
}
61+
}
62+
63+
public function getLogs(Request $request = null): array
64+
{
65+
if ($request) {
66+
return $this->logs[spl_object_hash($request)] ?? [];
67+
}
68+
69+
return array_merge(...array_values($this->logs));
70+
}
71+
72+
public function countErrors(Request $request = null): int
73+
{
74+
if ($request) {
75+
return $this->errorCount[spl_object_hash($request)] ?? 0;
76+
}
77+
78+
return array_sum($this->errorCount);
79+
}
80+
81+
public function clear()
82+
{
83+
$this->logs = [];
84+
$this->errorCount = [];
85+
}
86+
}

0 commit comments

Comments
 (0)