Skip to content
This repository was archived by the owner on Jan 23, 2019. It is now read-only.

Commit 7b1ec0f

Browse files
committed
up
1 parent b0adc41 commit 7b1ec0f

File tree

2 files changed

+256
-8
lines changed

2 files changed

+256
-8
lines changed

src/Components/ErrorHandler.php

Lines changed: 245 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,245 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Monolog package.
5+
*
6+
* (c) Jordi Boggiano <j.boggiano@seld.be>
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 Inhere\Library\Components;
13+
14+
use Inhere\Library\Helpers\PhpHelper;
15+
use Monolog\Logger;
16+
use Psr\Log\LoggerInterface;
17+
use Psr\Log\LogLevel;
18+
use Monolog\Handler\AbstractHandler;
19+
20+
/**
21+
* Monolog error handler
22+
*
23+
* A facility to enable logging of runtime errors, exceptions and fatal errors.
24+
*
25+
* Quick setup: <code>ErrorHandler::register($logger);</code>
26+
*
27+
* @author Jordi Boggiano <j.boggiano@seld.be>
28+
*/
29+
class ErrorHandler
30+
{
31+
private $logger;
32+
33+
private $previousExceptionHandler;
34+
private $uncaughtExceptionLevel;
35+
36+
private $previousErrorHandler;
37+
private $errorLevelMap;
38+
private $handleOnlyReportedErrors;
39+
40+
private $hasFatalErrorHandler;
41+
private $fatalLevel;
42+
private $reservedMemory;
43+
private static $fatalErrors = [E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR];
44+
45+
/**
46+
* ErrorHandler constructor.
47+
* @param LoggerInterface $logger
48+
*/
49+
public function __construct(LoggerInterface $logger)
50+
{
51+
$this->logger = $logger;
52+
}
53+
54+
/**
55+
* Registers a new ErrorHandler for a given Logger
56+
*
57+
* By default it will handle errors, exceptions and fatal errors
58+
*
59+
* @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
60+
* @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling
61+
* @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling
62+
* @return ErrorHandler
63+
*/
64+
public function register(array $errorLevelMap = [], $exceptionLevel = null, $fatalLevel = null)
65+
{
66+
//Forces the autoloader to run for LogLevel. Fixes an autoload issue at compile-time on PHP5.3. See https://github.com/Seldaek/monolog/pull/929
67+
class_exists(LogLevel::class);
68+
69+
if ($errorLevelMap !== false) {
70+
$this->registerErrorHandler($errorLevelMap);
71+
}
72+
if ($exceptionLevel !== false) {
73+
$this->registerExceptionHandler($exceptionLevel);
74+
}
75+
if ($fatalLevel !== false) {
76+
$this->registerFatalHandler($fatalLevel);
77+
}
78+
79+
return $this;
80+
}
81+
82+
public function registerExceptionHandler($level = null, $callPrevious = true)
83+
{
84+
$prev = set_exception_handler(array($this, 'handleException'));
85+
$this->uncaughtExceptionLevel = $level;
86+
if ($callPrevious && $prev) {
87+
$this->previousExceptionHandler = $prev;
88+
}
89+
}
90+
91+
public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1, $handleOnlyReportedErrors = true)
92+
{
93+
$prev = set_error_handler(array($this, 'handleError'), $errorTypes);
94+
$this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
95+
if ($callPrevious) {
96+
$this->previousErrorHandler = $prev ?: true;
97+
}
98+
99+
$this->handleOnlyReportedErrors = $handleOnlyReportedErrors;
100+
}
101+
102+
public function registerFatalHandler($level = null, $reservedMemorySize = 20)
103+
{
104+
register_shutdown_function(array($this, 'handleFatalError'));
105+
106+
$this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
107+
$this->fatalLevel = $level;
108+
$this->hasFatalErrorHandler = true;
109+
}
110+
111+
protected function defaultErrorLevelMap()
112+
{
113+
return array(
114+
E_ERROR => LogLevel::CRITICAL,
115+
E_WARNING => LogLevel::WARNING,
116+
E_PARSE => LogLevel::ALERT,
117+
E_NOTICE => LogLevel::NOTICE,
118+
E_CORE_ERROR => LogLevel::CRITICAL,
119+
E_CORE_WARNING => LogLevel::WARNING,
120+
E_COMPILE_ERROR => LogLevel::ALERT,
121+
E_COMPILE_WARNING => LogLevel::WARNING,
122+
E_USER_ERROR => LogLevel::ERROR,
123+
E_USER_WARNING => LogLevel::WARNING,
124+
E_USER_NOTICE => LogLevel::NOTICE,
125+
E_STRICT => LogLevel::NOTICE,
126+
E_RECOVERABLE_ERROR => LogLevel::ERROR,
127+
E_DEPRECATED => LogLevel::NOTICE,
128+
E_USER_DEPRECATED => LogLevel::NOTICE,
129+
);
130+
}
131+
132+
/**
133+
* @private
134+
* @param \Throwable $e
135+
*/
136+
public function handleException($e)
137+
{
138+
$this->logger->log(
139+
$this->uncaughtExceptionLevel ?? LogLevel::ERROR,
140+
sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()),
141+
array('exception' => $e)
142+
);
143+
144+
if ($this->previousExceptionHandler) {
145+
PhpHelper::call($this->previousExceptionHandler, $e);
146+
}
147+
148+
exit(255);
149+
}
150+
151+
/**
152+
* @private
153+
* @param $code
154+
* @param $message
155+
* @param string $file
156+
* @param int $line
157+
* @param array $context
158+
* @return bool|mixed
159+
*/
160+
public function handleError($code, $message, $file = '', $line = 0, array $context = array())
161+
{
162+
if ($this->handleOnlyReportedErrors && !(error_reporting() & $code)) {
163+
return false;
164+
}
165+
166+
// fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
167+
if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
168+
$level = $this->errorLevelMap[$code] ?? LogLevel::CRITICAL;
169+
$this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
170+
}
171+
172+
if ($this->previousErrorHandler === true) {
173+
return false;
174+
}
175+
176+
if ($this->previousErrorHandler) {
177+
return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
178+
}
179+
180+
return false;
181+
}
182+
183+
/**
184+
* @private
185+
*/
186+
public function handleFatalError()
187+
{
188+
$this->reservedMemory = null;
189+
190+
$lastError = error_get_last();
191+
if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
192+
$this->logger->log(
193+
$this->fatalLevel ?? LogLevel::ALERT,
194+
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
195+
array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'])
196+
);
197+
198+
if ($this->logger instanceof Logger) {
199+
foreach ($this->logger->getHandlers() as $handler) {
200+
if ($handler instanceof AbstractHandler) {
201+
$handler->close();
202+
}
203+
}
204+
}
205+
}
206+
}
207+
208+
private static function codeToString($code)
209+
{
210+
switch ($code) {
211+
case E_ERROR:
212+
return 'E_ERROR';
213+
case E_WARNING:
214+
return 'E_WARNING';
215+
case E_PARSE:
216+
return 'E_PARSE';
217+
case E_NOTICE:
218+
return 'E_NOTICE';
219+
case E_CORE_ERROR:
220+
return 'E_CORE_ERROR';
221+
case E_CORE_WARNING:
222+
return 'E_CORE_WARNING';
223+
case E_COMPILE_ERROR:
224+
return 'E_COMPILE_ERROR';
225+
case E_COMPILE_WARNING:
226+
return 'E_COMPILE_WARNING';
227+
case E_USER_ERROR:
228+
return 'E_USER_ERROR';
229+
case E_USER_WARNING:
230+
return 'E_USER_WARNING';
231+
case E_USER_NOTICE:
232+
return 'E_USER_NOTICE';
233+
case E_STRICT:
234+
return 'E_STRICT';
235+
case E_RECOVERABLE_ERROR:
236+
return 'E_RECOVERABLE_ERROR';
237+
case E_DEPRECATED:
238+
return 'E_DEPRECATED';
239+
case E_USER_DEPRECATED:
240+
return 'E_USER_DEPRECATED';
241+
}
242+
243+
return 'Unknown PHP error';
244+
}
245+
}

src/Helpers/PhpHelper.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
namespace Inhere\Library\Helpers;
77

88
use Inhere\Exceptions\ExtensionMissException;
9+
use Swoole\Coroutine;
910

1011
/**
1112
* Class PhpHelper
@@ -71,12 +72,14 @@ public static function getLoadedExtension($zend_extensions = false): array
7172
public static function runtime($startTime, $startMem, array $info = [])
7273
{
7374
// 显示运行时间
74-
$info['time'] = number_format(microtime(true) - $startTime, 4) . 's';
75+
$info['runtime'] = number_format((microtime(true) - $startTime) * 1000, 2) . 'ms';
7576

76-
$startMem = array_sum(explode(' ', $startMem));
77-
$endMem = array_sum(explode(' ', memory_get_usage()));
77+
if ($startMem) {
78+
$startMem = array_sum(explode(' ', $startMem));
79+
$endMem = array_sum(explode(' ', memory_get_usage()));
7880

79-
$info['memory'] = number_format(($endMem - $startMem) / 1024) . 'kb';
81+
$info['memory'] = number_format(($endMem - $startMem) / 1024, 2) . 'kb';
82+
}
8083

8184
return $info;
8285
}
@@ -122,7 +125,7 @@ public static function setMuted(): void
122125
* Returns true when the runtime used is PHP and Xdebug is loaded.
123126
* @return boolean
124127
*/
125-
public static function hasXdebug(): bool
128+
public static function hasXDebug(): bool
126129
{
127130
return static::isPHP() && extension_loaded('xdebug');
128131
}
@@ -135,7 +138,7 @@ public static function hasXdebug(): bool
135138
* @param null|string $catcher
136139
* @return string the string representation of the exception.
137140
*/
138-
public static function exceptionToString($e, $clearHtml = false, $getTrace = false, $catcher = null): string
141+
public static function exceptionToString($e, $getTrace = true, $clearHtml = false, $catcher = null): string
139142
{
140143
if (!$getTrace) {
141144
$message = "Error: {$e->getMessage()}";
@@ -270,8 +273,8 @@ public static function call($cb, array $args = [])
270273
list($obj, $mhd) = $cb;
271274

272275
$ret = is_object($obj) ? $obj->$mhd(...$args) : $obj::$mhd(...$args);
273-
} elseif (method_exists('Swoole\Coroutine', 'call_user_func_array')) {
274-
$ret = \Swoole\Coroutine::call_user_func_array($cb, $args);
276+
} elseif (class_exists(Coroutine::class, false)) {
277+
$ret = Coroutine::call_user_func_array($cb, $args);
275278
} else {
276279
$ret = call_user_func_array($cb, $args);
277280
}

0 commit comments

Comments
 (0)