Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions lib/private/AppFramework/Bootstrap/Coordinator.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

namespace OC\AppFramework\Bootstrap;

use OC\Support\CrashReport\Registry;
use OC_App;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootstrap;
Expand All @@ -42,16 +43,21 @@ class Coordinator {
/** @var IServerContainer */
private $serverContainer;

/** @var Registry */
private $registry;

/** @var IEventDispatcher */
private $eventDispatcher;

/** @var ILogger */
private $logger;

public function __construct(IServerContainer $container,
Registry $registry,
IEventDispatcher $eventListener,
ILogger $logger) {
$this->serverContainer = $container;
$this->registry = $registry;
$this->eventDispatcher = $eventListener;
$this->logger = $logger;
}
Expand Down Expand Up @@ -102,6 +108,7 @@ public function runRegistration(): void {
* to the actual services
*/
$context->delegateCapabilityRegistrations($apps);
$context->delegateCrashReporterRegistrations($apps, $this->registry);
$context->delegateEventListenerRegistrations($this->eventDispatcher);
$context->delegateContainerRegistrations($apps);
$context->delegateMiddlewareRegistrations($apps);
Expand Down
35 changes: 35 additions & 0 deletions lib/private/AppFramework/Bootstrap/RegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
namespace OC\AppFramework\Bootstrap;

use Closure;
use OC\Support\CrashReport\Registry;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use OCP\EventDispatcher\IEventDispatcher;
Expand All @@ -37,6 +38,9 @@ class RegistrationContext {
/** @var array[] */
private $capabilities = [];

/** @var array[] */
private $crashReporters = [];

/** @var array[] */
private $services = [];

Expand Down Expand Up @@ -79,6 +83,13 @@ public function registerCapability(string $capability): void {
);
}

public function registerCrashReporter(string $reporterClass): void {
$this->context->registerCrashReporter(
$this->appId,
$reporterClass
);
}

public function registerService(string $name, callable $factory, bool $shared = true): void {
$this->context->registerService(
$this->appId,
Expand Down Expand Up @@ -129,6 +140,13 @@ public function registerCapability(string $appId, string $capability): void {
];
}

public function registerCrashReporter(string $appId, string $reporterClass): void {
$this->crashReporters[] = [
'appId' => $appId,
'class' => $reporterClass,
];
}

public function registerService(string $appId, string $name, callable $factory, bool $shared = true): void {
$this->services[] = [
"appId" => $appId,
Expand Down Expand Up @@ -189,6 +207,23 @@ public function delegateCapabilityRegistrations(array $apps): void {
}
}

/**
* @param App[] $apps
*/
public function delegateCrashReporterRegistrations(array $apps, Registry $registry): void {
foreach ($this->crashReporters as $registration) {
try {
$registry->registerLazy($registration['class']);
} catch (Throwable $e) {
$appId = $registration['appId'];
$this->logger->logException($e, [
'message' => "Error during crash reporter registration of $appId: " . $e->getMessage(),
'level' => ILogger::ERROR,
]);
}
}
}

public function delegateEventListenerRegistrations(IEventDispatcher $eventDispatcher): void {
foreach ($this->eventListeners as $registration) {
try {
Expand Down
66 changes: 65 additions & 1 deletion lib/private/Support/CrashReport/Registry.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?php

declare(strict_types=1);

/**
*
*
Expand All @@ -25,6 +28,9 @@
namespace OC\Support\CrashReport;

use Exception;
use OCP\AppFramework\QueryException;
use OCP\ILogger;
use OCP\IServerContainer;
use OCP\Support\CrashReport\ICollectBreadcrumbs;
use OCP\Support\CrashReport\IMessageReporter;
use OCP\Support\CrashReport\IRegistry;
Expand All @@ -33,9 +39,22 @@

class Registry implements IRegistry {

/** @var string[] */
private $lazyReporters = [];

/** @var IReporter[] */
private $reporters = [];

/** @var IServerContainer */
private $serverContainer;

/** @var ILogger */
private $logger;

public function __construct(IServerContainer $serverContainer) {
$this->serverContainer = $serverContainer;
}

/**
* Register a reporter instance
*
Expand All @@ -45,6 +64,10 @@ public function register(IReporter $reporter): void {
$this->reporters[] = $reporter;
}

public function registerLazy(string $class): void {
$this->lazyReporters[] = $class;
}

/**
* Delegate breadcrumb collection to all registered reporters
*
Expand All @@ -55,6 +78,8 @@ public function register(IReporter $reporter): void {
* @since 15.0.0
*/
public function delegateBreadcrumb(string $message, string $category, array $context = []): void {
$this->loadLazyProviders();

foreach ($this->reporters as $reporter) {
if ($reporter instanceof ICollectBreadcrumbs) {
$reporter->collect($message, $category, $context);
Expand All @@ -69,7 +94,8 @@ public function delegateBreadcrumb(string $message, string $category, array $con
* @param array $context
*/
public function delegateReport($exception, array $context = []): void {
/** @var IReporter $reporter */
$this->loadLazyProviders();

foreach ($this->reporters as $reporter) {
$reporter->report($exception, $context);
}
Expand All @@ -84,10 +110,48 @@ public function delegateReport($exception, array $context = []): void {
* @return void
*/
public function delegateMessage(string $message, array $context = []): void {
$this->loadLazyProviders();

foreach ($this->reporters as $reporter) {
if ($reporter instanceof IMessageReporter) {
$reporter->reportMessage($message, $context);
}
}
}

private function loadLazyProviders(): void {
$classes = $this->lazyReporters;
foreach ($classes as $class) {
try {
/** @var IReporter $reporter */
$reporter = $this->serverContainer->query($class);
} catch (QueryException $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
'message' => 'Could not load lazy crash reporter: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
/**
* Try to register the loaded reporter. Theoretically it could be of a wrong
* type, so we might get a TypeError here that we should catch.
*/
try {
$this->register($reporter);
} catch (Throwable $e) {
/*
* There is a circular dependency between the logger and the registry, so
* we can not inject it. Thus the static call.
*/
\OC::$server->getLogger()->logException($e, [
'message' => 'Could not register lazy crash reporter: ' . $e->getMessage(),
'level' => ILogger::FATAL,
]);
}
}
$this->lazyReporters = [];
}
}
10 changes: 10 additions & 0 deletions lib/public/AppFramework/Bootstrap/IRegistrationContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,16 @@ interface IRegistrationContext {
*/
public function registerCapability(string $capability): void;

/**
* Register an implementation of \OCP\Support\CrashReport\IReporter that
* will receive unhandled exceptions and throwables
*
* @param string $reporterClass
* @return void
* @since 20.0.0
*/
public function registerCrashReporter(string $reporterClass): void;

/**
* Register a service
*
Expand Down
7 changes: 7 additions & 0 deletions lib/public/Support/CrashReport/IRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,12 @@
namespace OCP\Support\CrashReport;

use Exception;
use OCP\AppFramework\Bootstrap\IRegistrationContext;
use Throwable;

/**
* @since 13.0.0
* @deprecated used internally only
*/
interface IRegistry {

Expand All @@ -40,6 +42,8 @@ interface IRegistry {
* @param IReporter $reporter
*
* @since 13.0.0
* @deprecated 20.0.0 use IRegistrationContext::registerCrashReporter
* @see IRegistrationContext::registerCrashReporter()
*/
public function register(IReporter $reporter): void;

Expand All @@ -50,6 +54,7 @@ public function register(IReporter $reporter): void;
* @param string $category
* @param array $context
*
* @deprecated used internally only
* @since 15.0.0
*/
public function delegateBreadcrumb(string $message, string $category, array $context = []): void;
Expand All @@ -60,6 +65,7 @@ public function delegateBreadcrumb(string $message, string $category, array $con
* @param Exception|Throwable $exception
* @param array $context
*
* @deprecated used internally only
* @since 13.0.0
*/
public function delegateReport($exception, array $context = []);
Expand All @@ -72,6 +78,7 @@ public function delegateReport($exception, array $context = []);
*
* @return void
*
* @deprecated used internally only
* @since 17.0.0
*/
public function delegateMessage(string $message, array $context = []): void;
Expand Down
3 changes: 3 additions & 0 deletions lib/public/Support/CrashReport/IReporter.php
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
<?php

declare(strict_types=1);

/**
*
*
Expand Down
6 changes: 6 additions & 0 deletions tests/lib/AppFramework/Bootstrap/CoordinatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
namespace lib\AppFramework\Bootstrap;

use OC\AppFramework\Bootstrap\Coordinator;
use OC\Support\CrashReport\Registry;
use OCP\App\IAppManager;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
Expand All @@ -46,6 +47,9 @@ class CoordinatorTest extends TestCase {
/** @var IServerContainer|MockObject */
private $serverContainer;

/** @var Registry|MockObject */
private $crashReporterRegistry;

/** @var IEventDispatcher|MockObject */
private $eventDispatcher;

Expand All @@ -60,11 +64,13 @@ protected function setUp(): void {

$this->appManager = $this->createMock(IAppManager::class);
$this->serverContainer = $this->createMock(IServerContainer::class);
$this->crashReporterRegistry = $this->createMock(Registry::class);
$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
$this->logger = $this->createMock(ILogger::class);

$this->coordinator = new Coordinator(
$this->serverContainer,
$this->crashReporterRegistry,
$this->eventDispatcher,
$this->logger
);
Expand Down
Loading