|
2 | 2 |
|
3 | 3 | namespace Sentry\Laravel;
|
4 | 4 |
|
| 5 | +use Illuminate\Database\Eloquent\Model; |
| 6 | +use Illuminate\Database\LazyLoadingViolationException; |
5 | 7 | use Illuminate\Routing\Route;
|
6 | 8 | use Sentry\EventHint;
|
7 | 9 | use Sentry\EventId;
|
8 | 10 | use Sentry\ExceptionMechanism;
|
| 11 | +use Sentry\Laravel\Features\Concerns\ResolvesEventOrigin; |
9 | 12 | use Sentry\SentrySdk;
|
| 13 | +use Sentry\Severity; |
10 | 14 | use Sentry\Tracing\TransactionSource;
|
11 | 15 | use Throwable;
|
12 | 16 | use function Sentry\addBreadcrumb;
|
@@ -190,6 +194,54 @@ public static function captureUnhandledException(Throwable $throwable): ?EventId
|
190 | 194 | return SentrySdk::getCurrentHub()->captureException($throwable, $hint);
|
191 | 195 | }
|
192 | 196 |
|
| 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 | + |
193 | 245 | /**
|
194 | 246 | * Try to make an educated guess if the call came from the Laravel `report` helper.
|
195 | 247 | *
|
|
0 commit comments