fix: add recursion guard to prevent 100% CPU when STDOUT/STDERR is broken

When the terminal (IDE) is closed without stopping the framework first,
the PTY is destroyed and STDOUT/STDERR become broken file descriptors.
Any subsequent log call via echo/fwrite fails with E_WARNING, the error
handler catches it and calls the logger again, creating a recursive loop
that consumes 100% CPU.

Changes:
- Add static $in_log recursion guard flag to ConsoleLogger
- Wrap log output (echo/fwrite/fflush) with the guard and @ suppression
- Bump version from 1.1.6 to 1.1.7
This commit is contained in:
crazywhalecc
2026-06-17 14:30:50 +08:00
committed by Jerry Ma
parent ac5fa59428
commit d79edcef53

View File

@@ -10,7 +10,7 @@ use Psr\Log\LogLevel;
class ConsoleLogger extends AbstractLogger class ConsoleLogger extends AbstractLogger
{ {
public const VERSION = '1.1.6'; public const VERSION = '1.1.7';
/** /**
* 日志输出格式 * 日志输出格式
@@ -86,6 +86,13 @@ class ConsoleLogger extends AbstractLogger
*/ */
protected $stream; protected $stream;
/**
* 递归保护标志 — 防止日志写入失败时错误处理器再次调用日志导致死循环 CPU 100%
*
* @var bool
*/
protected static $in_log = false;
/** /**
* 是否带颜色 * 是否带颜色
* *
@@ -242,17 +249,27 @@ class ConsoleLogger extends AbstractLogger
} else { } else {
$output = $output . PHP_EOL; $output = $output . PHP_EOL;
} }
// use stream // 递归保护:如果上一次日志写入触发了错误(如终端关闭后 STDOUT/STDERR 破损),
if ($this->stream) { // 跳过本次输出,防止错误处理器递归调用导致 CPU 100% 空耗
fwrite($this->stream, $output); if (self::$in_log) {
fflush($this->stream); return;
} else { }
if ($level <= 4 && $this->use_stderr) { self::$in_log = true;
fwrite(STDERR, $output); try {
// use stream
if ($this->stream) {
@fwrite($this->stream, $output);
@fflush($this->stream);
} else { } else {
// use plain text output if ($level <= 4 && $this->use_stderr) {
echo $output; @fwrite(STDERR, $output);
} else {
// use plain text output
@echo $output;
}
} }
} finally {
self::$in_log = false;
} }
} }