Skip to content

Commit 04bad6b

Browse files
authored
Add helper to report lazy loading violations (#678)
1 parent 26d147b commit 04bad6b

File tree

2 files changed

+58
-0
lines changed

2 files changed

+58
-0
lines changed

src/Sentry/Laravel/Features/Concerns/ResolvesEventOrigin.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22

33
namespace Sentry\Laravel\Features\Concerns;
44

5+
use Illuminate\Contracts\Container\Container;
56
use Sentry\Laravel\Tracing\BacktraceHelper;
67

78
trait ResolvesEventOrigin
89
{
10+
protected function container(): Container
11+
{
12+
return app();
13+
}
14+
915
protected function resolveEventOrigin(): ?string
1016
{
1117
$backtraceHelper = $this->makeBacktraceHelper();

src/Sentry/Laravel/Integration.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@
22

33
namespace Sentry\Laravel;
44

5+
use Illuminate\Database\Eloquent\Model;
6+
use Illuminate\Database\LazyLoadingViolationException;
57
use Illuminate\Routing\Route;
68
use Sentry\EventHint;
79
use Sentry\EventId;
810
use Sentry\ExceptionMechanism;
11+
use Sentry\Laravel\Features\Concerns\ResolvesEventOrigin;
912
use Sentry\SentrySdk;
13+
use Sentry\Severity;
1014
use Sentry\Tracing\TransactionSource;
1115
use Throwable;
1216
use function Sentry\addBreadcrumb;
@@ -190,6 +194,54 @@ public static function captureUnhandledException(Throwable $throwable): ?EventId
190194
return SentrySdk::getCurrentHub()->captureException($throwable, $hint);
191195
}
192196

197+
/**
198+
* Returns a callback that can be passed to `Model::handleLazyLoadingViolationUsing` to report lazy loading violations to Sentry.
199+
*
200+
* @param callable|null $callback Optional callback to be called after the violation is reported to Sentry.
201+
*
202+
* @return callable
203+
*/
204+
public static function lazyLoadingViolationReporter(?callable $callback = null): callable
205+
{
206+
return new class($callback) {
207+
use ResolvesEventOrigin;
208+
209+
/** @var callable|null $callback */
210+
private $callback;
211+
212+
public function __construct(?callable $callback)
213+
{
214+
$this->callback = $callback;
215+
}
216+
217+
public function __invoke(Model $model, string $relation): void
218+
{
219+
SentrySdk::getCurrentHub()->withScope(function (Scope $scope) use ($model, $relation) {
220+
$scope->setContext('violation', [
221+
'model' => get_class($model),
222+
'relation' => $relation,
223+
'origin' => $this->resolveEventOrigin(),
224+
]);
225+
226+
SentrySdk::getCurrentHub()->captureEvent(
227+
tap(Event::createEvent(), static function (Event $event) {
228+
$event->setLevel(Severity::warning());
229+
}),
230+
EventHint::fromArray([
231+
'exception' => new LazyLoadingViolationException($model, $relation),
232+
'mechanism' => new ExceptionMechanism(ExceptionMechanism::TYPE_GENERIC, true),
233+
])
234+
);
235+
});
236+
237+
// Forward the violation to the next handler if there is one
238+
if ($this->callback !== null) {
239+
call_user_func($this->callback, $model, $relation);
240+
}
241+
}
242+
};
243+
}
244+
193245
/**
194246
* Try to make an educated guess if the call came from the Laravel `report` helper.
195247
*

0 commit comments

Comments
 (0)