diff options
Diffstat (limited to 'src/ErrorHandler')
-rw-r--r-- | src/ErrorHandler/ErrorCodes.php | 84 | ||||
-rw-r--r-- | src/ErrorHandler/Logging.php | 104 | ||||
-rw-r--r-- | src/ErrorHandler/Middleware.php | 76 |
3 files changed, 264 insertions, 0 deletions
diff --git a/src/ErrorHandler/ErrorCodes.php b/src/ErrorHandler/ErrorCodes.php new file mode 100644 index 0000000..6ef2957 --- /dev/null +++ b/src/ErrorHandler/ErrorCodes.php @@ -0,0 +1,84 @@ +<?php + +namespace Jasny\ErrorHandler; + +use Psr\Log\LogLevel; + +/** + * Trait for using E_* error codes + */ +trait ErrorCodes +{ + /** + * Get the log level for an error code + * + * @param int $code E_* error code + * @return string + */ + protected function getLogLevel($code = null) + { + switch ($code) { + case E_STRICT: + case E_DEPRECATED: + case E_USER_DEPRECATED: + return LogLevel::INFO; + + case E_NOTICE: + case E_USER_NOTICE: + return LogLevel::NOTICE; + + case E_WARNING: + case E_CORE_WARNING: + case E_COMPILE_WARNING: + case E_USER_WARNING: + return LogLevel::WARNING; + + case E_PARSE: + case E_CORE_ERROR: + case E_COMPILE_ERROR: + return LogLevel::CRITICAL; + + default: + return LogLevel::ERROR; + } + } + + /** + * Turn an error code into a string + * + * @param int $code + * @return string + */ + protected function codeToString($code) + { + switch ($code) { + case E_ERROR: + case E_USER_ERROR: + case E_RECOVERABLE_ERROR: + return 'Fatal error'; + case E_WARNING: + case E_USER_WARNING: + return 'Warning'; + case E_PARSE: + return 'Parse error'; + case E_NOTICE: + case E_USER_NOTICE: + return 'Notice'; + case E_CORE_ERROR: + return 'Core error'; + case E_CORE_WARNING: + return 'Core warning'; + case E_COMPILE_ERROR: + return 'Compile error'; + case E_COMPILE_WARNING: + return 'Compile warning'; + case E_STRICT: + return 'Strict standards'; + case E_DEPRECATED: + case E_USER_DEPRECATED: + return 'Deprecated'; + } + + return 'Unknown error'; + } +}
\ No newline at end of file diff --git a/src/ErrorHandler/Logging.php b/src/ErrorHandler/Logging.php new file mode 100644 index 0000000..6d531bd --- /dev/null +++ b/src/ErrorHandler/Logging.php @@ -0,0 +1,104 @@ +<?php + +namespace Jasny\ErrorHandler; + +use Psr\Log\LoggerInterface; +use Psr\Log\LogLevel; +use Psr\Log\NullLogger; + +/** + * Trait for logging errors and exceptions + */ +trait Logging +{ + /** + * @var LoggerInterface + */ + protected $logger; + + + /** + * Set the logger for logging errors + * + * @param LoggerInterface $logger + */ + public function setLogger(LoggerInterface $logger) + { + $this->logger = $logger; + } + + /** + * Set the logger for logging errors + * + * @return LoggerInterface + */ + public function getLogger() + { + if (!isset($this->logger)) { + $this->logger = new NullLogger(); + } + + return $this->logger; + } + + + /** + * Log an error or exception + * + * @param \Exception|\Error $error + */ + public function log($error) + { + if ($error instanceof \Error || $error instanceof \ErrorException) { + return $this->logError($error); + } + + if ($error instanceof \Exception) { + return $this->logException($error); + } + + $message = "Unable to log a " . (is_object($error) ? get_class($error) . ' ' : '') . gettype($error); + $this->getLogger()->log(LogLevel::WARNING, $message); + } + + /** + * Log an error + * + * @param \Error|\ErrorException $error + */ + protected function logError($error) + { + $code = $error instanceof \ErrorException ? $error->getSeverity() : E_ERROR; + $level = $this->getLogLevel($code); + + $message = sprintf('%s: %s at %s line %s', $this->codeToString($code), $error->getMessage(), + $error->getFile(), $error->getLine()); + + $context = [ + 'error' => $error, + 'code' => $code, + 'message' => $error->getMessage(), + 'file' => $error->getFile(), + 'line' => $error->getLine() + ]; + + $this->getLogger()->log($level, $message, $context); + } + + /** + * Log an exception + * + * @param \Exception $exception + */ + protected function logException(\Exception $exception) + { + $level = $this->getLogLevel(); + + $message = sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($exception), $exception->getMessage(), + $exception->getFile(), $exception->getLine()); + + $context = compact('exception'); + + $this->getLogger()->log($level, $message, $context); + } +} diff --git a/src/ErrorHandler/Middleware.php b/src/ErrorHandler/Middleware.php new file mode 100644 index 0000000..710f6e7 --- /dev/null +++ b/src/ErrorHandler/Middleware.php @@ -0,0 +1,76 @@ +<?php + +namespace Jasny\ErrorHandler; + +use Jasny\ErrorHandler; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Message\ResponseInterface; + +/** + * Use error handler as middleware + */ +class Middleware +{ + /** + * @var ErrorHandler + */ + protected $errorHandler; + + /** + * Class constructor + * + * @param ErrorHandler $errorHandler + */ + public function __construct(ErrorHandler $errorHandler) + { + $this->errorHandler = $errorHandler; + } + + /** + * Run middleware action + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @param callback $next + * @return ResponseInterface + */ + public function __invoke(ServerRequestInterface $request, ResponseInterface $response, $next) + { + if (!is_callable($next)) { + throw new \InvalidArgumentException("'next' should be a callback"); + } + + try { + $nextResponse = $next($request, $response); + $error = null; + } catch (\Error $e) { + $error = $e; + } catch (\Exception $e) { + $error = $e; + } + + $this->errorHandler->setError($error); + + if ($error) { + $this->errorHandler->log($error); + $nextResponse = $this->errorResponse($request, $response); + } + + return $nextResponse; + } + + /** + * Handle caught error + * + * @param ServerRequestInterface $request + * @param ResponseInterface $response + * @return ResponseInterface + */ + protected function errorResponse(ServerRequestInterface $request, ResponseInterface $response) + { + $errorResponse = $response->withStatus(500); + $errorResponse->getBody()->write('Unexpected error'); + + return $errorResponse; + } +} |