summaryrefslogtreecommitdiffstats
path: root/src/ErrorHandler
diff options
context:
space:
mode:
Diffstat (limited to 'src/ErrorHandler')
-rw-r--r--src/ErrorHandler/ErrorCodes.php84
-rw-r--r--src/ErrorHandler/Logging.php104
-rw-r--r--src/ErrorHandler/Middleware.php76
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;
+ }
+}