Skip to content

Commit e5e633c

Browse files
committed
docs: improve exception handling docs
1 parent 10f4e27 commit e5e633c

File tree

1 file changed

+87
-4
lines changed

1 file changed

+87
-4
lines changed

docs/2-features/14-exception-handling.md

Lines changed: 87 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,9 @@ description: "Learn how exception handling works, how to manually report excepti
55

66
## Overview
77

8-
Tempest comes with its own exception handler, which provides a simple way to catch and process exceptions. During local development, Tempest uses [Whoops](https://github.com/filp/whoops) to display detailed error pages. In production, it displays a generic error page.
8+
Tempest comes with an exception handler that provides a simple way to report exceptions and render error responses.
99

10-
When an exception is thrown, it is caught and piped through the registered exception reporters. By default, the only registered exception reporter, {b`Tempest\Core\LoggingExceptionReporter`}, logs the exception.
11-
12-
Custom exception reporters can be created by implementing the {b`Tempest\Core\Exceptions\ExceptionReporter`} interface. Classes implementing this interface are automatically [discovered](../4-internals/02-discovery.md) and do not require manual registration.
10+
Custom [exception reporters](#writing-exception-reporters) can be created by implementing the {b`Tempest\Core\Exceptions\ExceptionReporter`} interface, and custom [exception renderers](#customizing-exception-rendering) can be created by implementing {b`Tempest\Router\Exceptions\ExceptionRenderer`}. These classes are automatically [discovered](../4-internals/02-discovery.md) and do not require manual registration.
1311

1412
## Processing exceptions
1513

@@ -70,6 +68,91 @@ final readonly class UserWasNotFound extends Exception implements ProvidesContex
7068
}
7169
```
7270

71+
## Writing exception reporters
72+
73+
Exception reporters allow defining custom reporting logic for exceptions, such as sending them to external error tracking services like Sentry or logging them to specific destinations.
74+
75+
To create a custom reporter, implement the {b`Tempest\Core\Exceptions\ExceptionReporter`} interface and define a `report()` method:
76+
77+
```php app/SentryExceptionReporter.php
78+
use Tempest\Core\Exceptions\ExceptionReporter;
79+
use Throwable;
80+
81+
final class SentryExceptionReporter implements ExceptionReporter
82+
{
83+
public function __construct(
84+
private SentryClient $sentry,
85+
) {}
86+
87+
public function report(Throwable $throwable): void
88+
{
89+
$this->sentry->captureException($throwable);
90+
}
91+
}
92+
```
93+
94+
Exception reporters are automatically [discovered](../4-internals/02-discovery.md) and registered. All registered reporters are invoked whenever an exception is processed, allowing multiple reporters to handle the same exception.
95+
96+
For example, the default logging reporter logs to a file, while the reporter above sends the error to Sentry.
97+
98+
If an exception reporter throws an exception during execution, it is silently caught to prevent infinite loops. This ensures that a failing reporter doesn't prevent other reporters from running.
99+
100+
### Accessing exception context
101+
102+
Exceptions can implement the {b`Tempest\Core\ProvidesContext`} interface, which reporters can leverage to provide additional context data during reporting:
103+
104+
```php app/SentryExceptionReporter.php
105+
use Tempest\Core\Exceptions\ExceptionReporter;
106+
use Tempest\Core\ProvidesContext;
107+
use Sentry\State\HubInterface as Sentry;
108+
use Sentry\State\Scope;
109+
110+
final class SentryExceptionReporter implements ExceptionReporter
111+
{
112+
public function __construct(
113+
private readonly Sentry $sentry,
114+
) {}
115+
116+
public function report(Throwable $throwable): void
117+
{
118+
$this->sentry->withScope(function (Scope $scope) use ($throwable) {
119+
if ($throwable instanceof ProvidesContext) {
120+
$scope->withContext($throwable->context());
121+
}
122+
123+
$scope->captureException($throwable);
124+
});
125+
}
126+
}
127+
```
128+
129+
### Conditional reporting
130+
131+
Reporters can implement conditional logic to only report specific exception types or under certain conditions. There is no built-in filtering mechanism; reporters are responsible for determining when to report an exception.
132+
133+
```php app/CriticalErrorReporter.php
134+
use Tempest\Core\Exceptions\ExceptionReporter;
135+
use Throwable;
136+
137+
final class CriticalErrorReporter implements ExceptionReporter
138+
{
139+
public function __construct(
140+
private AlertService $alerts,
141+
) {}
142+
143+
public function report(Throwable $throwable): void
144+
{
145+
if (! $throwable instanceof CriticalException) {
146+
return;
147+
}
148+
149+
$this->alerts->sendCriticalAlert(
150+
message: $throwable->getMessage(),
151+
);
152+
}
153+
}
154+
```
155+
73156
## Customizing exception rendering
74157

75158
Exception renderers provide control over how exceptions are rendered in HTTP responses. Custom renderers can be used to display specialized error pages for specific exception types, format errors differently based on content type (JSON, HTML, XML), or provide user-friendly error messages for common scenarios like 404 or validation failures.

0 commit comments

Comments
 (0)