Quick Start
composer require kirschbaum-development/monitor
php artisan vendor:publish --tag=monitor-config
Add the trace middleware so every request, and every job it dispatches, shares one trace id:
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
$middleware->append(\Kirschbaum\Monitor\Http\Middleware\StartTrace::class);
})
Declare a critical operation as a class:
php artisan make:control-point Payments/ChargeCard --profile=external
#[Point('payments.charge_card', profile: 'external')]
final class ChargeCard extends ControlPoint
{
public function __construct(private readonly Invoice $invoice) {}
protected function control(Control $control): void
{
$control
->recover(CardDeclined::class, fn (CardDeclined $e) => ChargeResult::declined($e->code))
->ensure(fn (ChargeResult $r): bool => $r->settled, 'charge must be settled')
->escalate(PagePayments::class);
}
public function context(): array
{
return ['invoice' => $this->invoice->id];
}
public function handle(StripeClient $stripe): ChargeResult
{
return $stripe->charge($this->invoice);
}
}
ChargeCard::run($invoice); // the value, or throws what escaped
ChargeCard::attempt($invoice); // an Outcome: ->status, ->value, ->exception, ->attempts, ->durationMs
Test it by name:
Monitor::fake()->failing('payments.charge_card', new CardDeclined('insufficient_funds'));
ChargeCard::run($invoice);
Monitor::assertRecovered('payments.charge_card', from: CardDeclined::class);
Monitor::assertNothingEscalated();
And prove in CI that every critical operation is declared and complete:
php artisan monitor:points --check