ErrorHandler.php 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
  5. * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
  6. * SPDX-License-Identifier: AGPL-3.0-only
  7. */
  8. namespace OC\Log;
  9. use Error;
  10. use OCP\ILogger;
  11. use Psr\Log\LoggerInterface;
  12. use Throwable;
  13. class ErrorHandler {
  14. public function __construct(
  15. private LoggerInterface $logger,
  16. ) {
  17. }
  18. /**
  19. * Remove password in URLs
  20. */
  21. private static function removePassword(string $msg): string {
  22. return preg_replace('#//(.*):(.*)@#', '//xxx:xxx@', $msg);
  23. }
  24. /**
  25. * Fatal errors handler
  26. */
  27. public function onShutdown(): void {
  28. $error = error_get_last();
  29. if ($error) {
  30. $msg = $error['message'] . ' at ' . $error['file'] . '#' . $error['line'];
  31. $this->logger->critical(self::removePassword($msg), ['app' => 'PHP']);
  32. }
  33. }
  34. /**
  35. * Uncaught exception handler
  36. */
  37. public function onException(Throwable $exception): void {
  38. $class = get_class($exception);
  39. $msg = $exception->getMessage();
  40. $msg = "$class: $msg at " . $exception->getFile() . '#' . $exception->getLine();
  41. $this->logger->critical(self::removePassword($msg), ['app' => 'PHP']);
  42. }
  43. /**
  44. * Recoverable errors handler
  45. */
  46. public function onError(int $number, string $message, string $file, int $line): bool {
  47. if (!(error_reporting() & $number)) {
  48. return true;
  49. }
  50. $msg = $message . ' at ' . $file . '#' . $line;
  51. $e = new Error(self::removePassword($msg));
  52. $this->logger->log(self::errnoToLogLevel($number), $e->getMessage(), ['app' => 'PHP']);
  53. return true;
  54. }
  55. /**
  56. * Recoverable handler which catch all errors, warnings and notices
  57. */
  58. public function onAll(int $number, string $message, string $file, int $line): bool {
  59. $msg = $message . ' at ' . $file . '#' . $line;
  60. $e = new Error(self::removePassword($msg));
  61. $this->logger->log(self::errnoToLogLevel($number), $e->getMessage(), ['app' => 'PHP']);
  62. return true;
  63. }
  64. private static function errnoToLogLevel(int $errno): int {
  65. return match ($errno) {
  66. E_USER_WARNING => ILogger::WARN,
  67. E_DEPRECATED, E_USER_DEPRECATED => ILogger::DEBUG,
  68. E_USER_NOTICE => ILogger::INFO,
  69. default => ILogger::ERROR,
  70. };
  71. }
  72. }