Skip to content

Commit 4700939

Browse files
committed
feat: Opt-in logging of deprecations
1 parent 5e85901 commit 4700939

File tree

3 files changed

+105
-0
lines changed

3 files changed

+105
-0
lines changed

app/Config/Exceptions.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
namespace Config;
44

55
use CodeIgniter\Config\BaseConfig;
6+
use Psr\Log\LogLevel;
67

78
/**
89
* Setup how the exception handler works.
@@ -49,4 +50,28 @@ class Exceptions extends BaseConfig
4950
* ex. ['server', 'setup/password', 'secret_token']
5051
*/
5152
public array $sensitiveDataInTrace = [];
53+
54+
/**
55+
* --------------------------------------------------------------------------
56+
* LOG DEPRECATIONS INSTEAD OF THROWING?
57+
* --------------------------------------------------------------------------
58+
* By default, CodeIgniter converts deprecations into exceptions. Also,
59+
* starting in PHP 8.1 will cause a lot of deprecated usage warnings.
60+
* Use this option to temporarily cease the warnings ang instead log those.
61+
* This option also works for user deprecations.
62+
*/
63+
public bool $logDeprecationsOnly = false;
64+
65+
/**
66+
* --------------------------------------------------------------------------
67+
* LOG LEVEL THRESHOLD FOR DEPRECATIONS
68+
* --------------------------------------------------------------------------
69+
* If `$logDeprecationsOnly` is set to `true`, this sets the log level
70+
* to which the deprecation will be logged. This should be one of the log
71+
* levels recognized by PSR-3.
72+
*
73+
* The related `Config\Logger::$threshold` should be adjusted, if needed,
74+
* to capture logging the deprecations.
75+
*/
76+
public string $deprecationLogLevel = LogLevel::WARNING;
5277
}

system/Debug/Exceptions.php

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@ public function __construct(ExceptionsConfig $config, $request, ResponseInterfac
8282
if (! isset($this->config->sensitiveDataInTrace)) {
8383
$this->config->sensitiveDataInTrace = [];
8484
}
85+
if (! isset($this->config->logDeprecationsOnly, $this->config->deprecationLogLevel)) {
86+
$this->config->logDeprecationsOnly = false;
87+
$this->config->deprecationLogLevel = 'warning';
88+
}
8589
}
8690

8791
/**
@@ -155,6 +159,10 @@ public function exceptionHandler(Throwable $exception)
155159
*/
156160
public function errorHandler(int $severity, string $message, ?string $file = null, ?int $line = null)
157161
{
162+
if ($this->isDeprecationError($severity) && $this->config->logDeprecationsOnly) {
163+
return $this->deprecationErrorHandler($message, $file, $line);
164+
}
165+
158166
if (! (error_reporting() & $severity)) {
159167
return;
160168
}
@@ -328,6 +336,29 @@ protected function determineCodes(Throwable $exception): array
328336
return [$statusCode, $exitStatus];
329337
}
330338

339+
private function isDeprecationError(int $error): bool
340+
{
341+
$deprecations = E_DEPRECATED | E_USER_DEPRECATED;
342+
343+
return ($error & $deprecations) !== 0;
344+
}
345+
346+
private function deprecationErrorHandler(string $message, ?string $file = null, ?int $line = null): bool
347+
{
348+
log_message(
349+
$this->config->deprecationLogLevel,
350+
"[DEPRECATED] {message} in {errFile} on line {errLine}.\n{trace}",
351+
[
352+
'message' => $message,
353+
'errFile' => clean_path($file ?? ''),
354+
'errLine' => $line ?? 0,
355+
'trace' => self::renderBacktrace(debug_backtrace()),
356+
]
357+
);
358+
359+
return true;
360+
}
361+
331362
// --------------------------------------------------------------------
332363
// Display Methods
333364
// --------------------------------------------------------------------

tests/system/Debug/ExceptionsTest.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use CodeIgniter\Test\ReflectionHelper;
2020
use Config\Exceptions as ExceptionsConfig;
2121
use Config\Services;
22+
use ErrorException;
2223
use RuntimeException;
2324

2425
/**
@@ -32,9 +33,57 @@ final class ExceptionsTest extends CIUnitTestCase
3233

3334
protected function setUp(): void
3435
{
36+
parent::setUp();
37+
3538
$this->exception = new Exceptions(new ExceptionsConfig(), Services::request(), Services::response());
3639
}
3740

41+
/**
42+
* @requires PHP >= 8.1
43+
*/
44+
public function testDeprecationsDoNotThrow(): void
45+
{
46+
$config = new ExceptionsConfig();
47+
48+
$config->logDeprecationsOnly = true;
49+
$config->deprecationLogLevel = 'error';
50+
51+
$this->exception = new Exceptions($config, Services::request(), Services::response());
52+
$this->exception->initialize();
53+
54+
$maybeNull = 'random string';
55+
if (PHP_VERSION_ID >= 80100) {
56+
$maybeNull = null;
57+
}
58+
59+
try {
60+
strlen($maybeNull);
61+
$this->assertLogged('error', '[DEPRECATED] strlen(): ', false);
62+
} catch (ErrorException $e) {
63+
$this->fail('The catch block should not be reached.');
64+
} finally {
65+
restore_error_handler();
66+
restore_exception_handler();
67+
}
68+
}
69+
70+
public function testSuppressedDeprecationsDoNotThrow(): void
71+
{
72+
$config = new ExceptionsConfig();
73+
74+
$config->logDeprecationsOnly = true;
75+
$config->deprecationLogLevel = 'error';
76+
77+
$this->exception = new Exceptions($config, Services::request(), Services::response());
78+
$this->exception->initialize();
79+
80+
@trigger_error('Hello! I am a deprecation!', E_USER_DEPRECATED);
81+
$this->assertLogged('error', '[DEPRECATED] Hello! I am a deprecation!', false);
82+
83+
restore_error_handler();
84+
restore_exception_handler();
85+
}
86+
3887
public function testDetermineViews(): void
3988
{
4089
$determineView = $this->getPrivateMethodInvoker($this->exception, 'determineView');

0 commit comments

Comments
 (0)