Registry.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * @copyright Copyright (c) 2016 Christoph Wurst <christoph@winzerhof-wurst.at>
  5. *
  6. * @author Christoph Wurst <christoph@winzerhof-wurst.at>
  7. * @author Morris Jobke <hey@morrisjobke.de>
  8. *
  9. * @license GNU AGPL version 3 or any later version
  10. *
  11. * This program is free software: you can redistribute it and/or modify
  12. * it under the terms of the GNU Affero General Public License as
  13. * published by the Free Software Foundation, either version 3 of the
  14. * License, or (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU Affero General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU Affero General Public License
  22. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  23. *
  24. */
  25. namespace OC\Support\CrashReport;
  26. use Exception;
  27. use OCP\AppFramework\QueryException;
  28. use OCP\IServerContainer;
  29. use OCP\Support\CrashReport\ICollectBreadcrumbs;
  30. use OCP\Support\CrashReport\IMessageReporter;
  31. use OCP\Support\CrashReport\IRegistry;
  32. use OCP\Support\CrashReport\IReporter;
  33. use Psr\Log\LoggerInterface;
  34. use Throwable;
  35. use function array_shift;
  36. class Registry implements IRegistry {
  37. /** @var string[] */
  38. private $lazyReporters = [];
  39. /** @var IReporter[] */
  40. private $reporters = [];
  41. /** @var IServerContainer */
  42. private $serverContainer;
  43. public function __construct(IServerContainer $serverContainer) {
  44. $this->serverContainer = $serverContainer;
  45. }
  46. /**
  47. * Register a reporter instance
  48. *
  49. * @param IReporter $reporter
  50. */
  51. public function register(IReporter $reporter): void {
  52. $this->reporters[] = $reporter;
  53. }
  54. public function registerLazy(string $class): void {
  55. $this->lazyReporters[] = $class;
  56. }
  57. /**
  58. * Delegate breadcrumb collection to all registered reporters
  59. *
  60. * @param string $message
  61. * @param string $category
  62. * @param array $context
  63. *
  64. * @since 15.0.0
  65. */
  66. public function delegateBreadcrumb(string $message, string $category, array $context = []): void {
  67. $this->loadLazyProviders();
  68. foreach ($this->reporters as $reporter) {
  69. if ($reporter instanceof ICollectBreadcrumbs) {
  70. $reporter->collect($message, $category, $context);
  71. }
  72. }
  73. }
  74. /**
  75. * Delegate crash reporting to all registered reporters
  76. *
  77. * @param Exception|Throwable $exception
  78. * @param array $context
  79. */
  80. public function delegateReport($exception, array $context = []): void {
  81. $this->loadLazyProviders();
  82. foreach ($this->reporters as $reporter) {
  83. $reporter->report($exception, $context);
  84. }
  85. }
  86. /**
  87. * Delegate a message to all reporters that implement IMessageReporter
  88. *
  89. * @param string $message
  90. * @param array $context
  91. *
  92. * @return void
  93. */
  94. public function delegateMessage(string $message, array $context = []): void {
  95. $this->loadLazyProviders();
  96. foreach ($this->reporters as $reporter) {
  97. if ($reporter instanceof IMessageReporter) {
  98. $reporter->reportMessage($message, $context);
  99. }
  100. }
  101. }
  102. private function loadLazyProviders(): void {
  103. while (($class = array_shift($this->lazyReporters)) !== null) {
  104. try {
  105. /** @var IReporter $reporter */
  106. $reporter = $this->serverContainer->query($class);
  107. } catch (QueryException $e) {
  108. /*
  109. * There is a circular dependency between the logger and the registry, so
  110. * we can not inject it. Thus the static call.
  111. */
  112. \OC::$server->get(LoggerInterface::class)->critical('Could not load lazy crash reporter: ' . $e->getMessage(), [
  113. 'exception' => $e,
  114. ]);
  115. }
  116. /**
  117. * Try to register the loaded reporter. Theoretically it could be of a wrong
  118. * type, so we might get a TypeError here that we should catch.
  119. */
  120. try {
  121. $this->register($reporter);
  122. } catch (Throwable $e) {
  123. /*
  124. * There is a circular dependency between the logger and the registry, so
  125. * we can not inject it. Thus the static call.
  126. */
  127. \OC::$server->get(LoggerInterface::class)->critical('Could not register lazy crash reporter: ' . $e->getMessage(), [
  128. 'exception' => $e,
  129. ]);
  130. }
  131. }
  132. }
  133. public function hasReporters(): bool {
  134. return !empty($this->lazyReporters) || !empty($this->reporters);
  135. }
  136. }