kirschbaum-development/monitor
Monitor is a Laravel package from Kirschbaum Development that helps you keep tabs on your application's health and performance. It offers a lightweight, configurable way to add monitoring and catch issues before they affect your users or services. Designed for simple setup and integration into exist...
Architecture fit. This is a control-flow and policy layer, not an observability backend. It sits between the domain code and the side effect: you declare what an operation tolerates (recover), what it guarantees (ensure), how long it may take (within), how often it may retry (attempts/once), and who is paged (escalate). It complements an existing APM rather than competing with it — StartTrace reads and writes W3C traceparent, Http::traced() propagates it outbound, and trace state lives in Laravel's Context, so Monitor records land inside the trace we already have. If we run Sentry/Datadog/OTel, the purchase here is the declaration-plus-verification layer, not the transport.
Integration feasibility. Genuinely low-risk to install. Requires PHP 8.3–8.5 and Laravel 12/13 (Laravel 11 dropped), with a hard dependency on kirschbaum-development/redactor 1.x. The service provider is deliberately inert at boot — commands and publishing behind runningInConsole(), the migration published but never auto-loaded, middleware aliases resolved lazily, store and MCP off by default. Nothing changes in behaviour until someone declares a point. That makes a time-boxed spike cheap and fully reversible.
Technical risk. Adoption, not engineering. Three stars and zero dependents means v1.0.0 has essentially no production mileage anywhere, and it shipped as a full rewrite with no compatibility layer — so we would be an early adopter with no community-sourced bug reports to lean on. Support concentrates on a single vendor agency (credible in the Laravel ecosystem, but this is not a funded platform). The version window is narrow and coupled to the newest framework. The pipeline order (breaker → retry → transaction) is fixed; custom policies implement one interface but cannot be reordered. The concept surface is large for a team to absorb.
Key questions.
BreakerOpened alerting must be mandatory, not a nice-to-have.Stack fit. Idiomatic Laravel throughout: facade with Conditionable/Macroable, container-resolved corrections, contracts in Contracts\, commands in Console\Commands\, final readonly value objects implementing Arrayable/JsonSerializable, publishesMigrations(), and store flushes hooked where first-party packages flush (kernels, per-job, Queue::looping, Octane-safe). Event-first design — eleven events with log lines and the store as listeners — means existing Monolog handlers and redaction keep working untouched.
Migration path. There is no 0.1-to-1.0 path, but that is irrelevant to us: we adopt at 1.0 greenfield. Migration of our own code is per-operation and incremental — inline Monitor::control('payment.charge', $this) proves the pattern inside one existing method, then promotes to a #[Point]-annotated ControlPoint class when the contract earns its own file. make:control-point generates the class plus a test that already uses Monitor::fake(), so the first commit is correct by construction.
Compatibility. The monitor:points SARIF output plugs into GitHub code scanning, so findings land where security and quality already report. The Pest expectations (toBeControlled(), toHaveCompleteControlPoints()) and the PHPStan rule (monitor.uncontrolled) reuse static-analysis budget we already pay. MonitorFake implements Laravel's Fake contract, matching Http::fake() idioms the team already knows. monitor_outcomes is a plain table with a published, versioned schema (monitor/1), and JsonTap/RecordFormatter give an NDJSON escape hatch if we would rather not own a table.
Sequencing.
monitor:points to CI in report-only mode with SARIF upload; make --check blocking only after the backlog of findings is cleared.recover/ensure/escalate contracts.once() idempotency last — both need shared cache and a thought-through retry-after story.Maintenance. Per-operation cost is low: declare once, the pipeline is handled. The recurring cost is version drift — the package tracks the newest Laravel, so framework upgrades and Monitor upgrades become coupled, and v1.0.0's wholesale removal of 0.1 establishes a precedent that majors break.
Support. MIT, no SLA. The vendor's reputation is good, but the installed base is effectively zero, so we are the bug report. The mitigation is unusually strong and deserves credit: guidelines at .ai/guidelines/, a Boost skill, an MCP server with list_points/explain_point/outcomes/escalations, and redacted-by-default responses mean our own agents can self-serve the convention and audit existing points rather than relying on vendor responsiveness.
Scaling. Store writes are deliberately off the request path — flushed after the response or job, or at a buffer of 100 — so no added p99. Record volume scales with point invocations times transitions: a high-traffic point that retries emits several records per run, so budget log/storage growth per domain before enabling globally. Breaker state in cache makes the circuit correct across processes at the cost of a cache dependency, and we need to know explicitly whether a cache outage fails open or closed.
Failure modes — and this is the design's strongest area, because blast radius is bounded everywhere:
EscalationFailed and the original exception still propagates.attempts() caps retries regardless of what policies request — no retry storms.within() records a duration breach but never fails a completed run; ensure() fails after every policy and is never retried, so a "succeeded but wrong" result isn't retried pointlessly.once() releases the key on failure and keeps it on completion — correct for side effects, but completed-then-rolled-back is a case we must design for ourselves.Ramp-up. The real cost is conceptual — control point, outcome, terminal, risk/correction, escalation, limits, policies, profiles, nesting, breakers, records, fake, inventory. Expect roughly one engineer-week for a senior engineer to be fluent on a single domain. Generated scaffolding plus a pre-written fake-based test flattens the curve considerably, and the CI gate should stay report-only until that week has been absorbed — otherwise it blocks the team before it has taught them anything. Verdict: worth a two-domain pilot with a named owner, contingent on a shared cache, mandatory BreakerOpened alerting, and an accepted budget for breaking majors.
How can I help you explore Laravel packages today?