PHPackages                             kirschbaum-development/monitor - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Logging &amp; Monitoring](/categories/logging)
4. /
5. kirschbaum-development/monitor

ActiveLibrary[Logging &amp; Monitoring](/categories/logging)

kirschbaum-development/monitor
==============================

Laravel observability toolkit with critical control points, structured logging, performance timing, and trace context.

v0.1.3(12mo ago)21.6k↓85.7%[3 PRs](https://github.com/kirschbaum-development/monitor/pulls)MITPHPPHP ^8.3|^8.4CI passing

Since Jun 17Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/kirschbaum-development/monitor)[ Packagist](https://packagist.org/packages/kirschbaum-development/monitor)[ RSS](/packages/kirschbaum-development-monitor/feed)WikiDiscussions main Synced yesterday

READMEChangelog (4)Dependencies (9)Versions (10)Used By (0)

Laravel Monitor
===============

[](#laravel-monitor)

[![Laravel Supported Versions](https://camo.githubusercontent.com/4b685234c18c2a323630d28899a6df0f78314186029222a4483f21c9c9d9a506/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31302e782f31312e782f31322e782d677265656e2e737667)](https://camo.githubusercontent.com/4b685234c18c2a323630d28899a6df0f78314186029222a4483f21c9c9d9a506/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c61726176656c2d31302e782f31312e782f31322e782d677265656e2e737667)[![MIT Licensed](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.md)[![Latest Version on Packagist](https://camo.githubusercontent.com/fb799384bb15112e169288a03aaa6fec1c6592468e552c98016ba2d840752d19/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6b69727363686261756d2d646576656c6f706d656e742f6d6f6e69746f722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/kirschbaum-development/monitor)[![Application Testing](https://github.com/kirschbaum-development/monitor/actions/workflows/php-tests.yml/badge.svg)](https://github.com/kirschbaum-development/monitor/actions/workflows/php-tests.yml/badge.svg)[![Static Analysis](https://github.com/kirschbaum-development/monitor/actions/workflows/static-analysis.yml/badge.svg)](https://github.com/kirschbaum-development/monitor/actions/workflows/static-analysis.yml/badge.svg)[![Code Style](https://github.com/kirschbaum-development/monitor/actions/workflows/style-check.yml/badge.svg)](https://github.com/kirschbaum-development/monitor/actions/workflows/style-check.yml/badge.svg)

Laravel Monitor is an observability helper / toolkit for Laravel applications.

> This package is active development and its API can change abruptly without any notice. Please reach out if you plan to use it in a production environment.

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Components](#components)
    - [Structured Logging](#structured-logging)
    - [Controlled Execution Blocks](#controlled-execution-blocks)
    - [Distributed Tracing](#distributed-tracing)
    - [HTTP Middleware](#http-middleware)
    - [Performance Timing](#performance-timing)
    - [Circuit Breaker Direct Access](#circuit-breaker-direct-access)
    - [Log Redactor Direct Access](#log-redactor-direct-access)
    - [Log Redaction](#log-redaction)
- [Complete API Reference](#complete-api-reference)
- [Configuration](#configuration)
- [Output Examples](#output-examples)
- [Testing](#testing)
- [License](#license)

Installation
------------

[](#installation)

Install via Composer:

```
composer require kirschbaum-development/monitor
```

Publish configuration files:

```
php artisan vendor:publish --tag="monitor-config"
```

Components
----------

[](#components)

### Structured Logging

[](#structured-logging)

**What it does:** Enhances Laravel's logging with automatic enrichment (trace IDs, timing, memory usage, structured context) and smart origin resolution from class namespaces.

```
use Kirschbaum\Monitor\Facades\Monitor;

// In App\Http\Controllers\Api\UserController
class UserController extends Controller
{
    public function login(LoginRequest $request)
    {
        // Automatic origin resolution from full namespace
        Monitor::log($this)->info('User login attempt', [
            'email' => $request->email,
            'ip' => $request->ip()
        ]);
    }
}

// In App\Services\Payment\StripePaymentService
class StripePaymentService
{
    public function processPayment($amount)
    {
        // Origin automatically resolved to clean, readable format
        Monitor::log($this)->info('Processing payment', [
            'amount' => $amount,
            'processor' => 'stripe'
        ]);
    }
}
```

**Note:** While you can override with `Monitor::log('CustomName')`, using `log($this)` is preferred as it automatically provides meaningful, consistent origin tracking from your actual class structure.

**What it logs:**

```
{
    "level": "info",
    "event": "Monitor:Http:Controllers:Api:UserController:info",
    "message": "[Monitor:Http:Controllers:Api:UserController] User login attempt",
    "trace_id": "9d2b4e8f-3a1c-4d5e-8f2a-1b3c4d5e6f7g",
    "context": {
        "email": "[REDACTED]",
        "ip": "192.168.1.1"
    },
    "timestamp": "2024-01-15T14:30:45.123Z",
    "duration_ms": 245,
    "memory_mb": 45.23
}
```

**Note:** The `event` field uses the raw origin name (after path replacers but before wrapper), while the `message` field uses the wrapped origin name for readability.

**Configuration:** Origin path replacers, separators, and wrappers control how class names appear in logs:

```
// config/monitor.php
'origin_path_replacers' => [
    'App\\' => 'Monitor\\',                  // Default: Replace App\ with Monitor\
    // 'App\\Http\\Controllers\\' => '',     // Example: Remove controller namespace
    // 'App\\Services\\Payment\\' => 'Pay\\', // Example: Shorten payment services
    // 'App\\Services\\' => 'Svc\\',         // Example: General service shortening
],
'origin_separator' => ':',           // App\Http\Controllers\Api\UserController → Monitor:Http:Controllers:Api:UserController
'origin_path_wrapper' => 'square',   // Monitor:Http:Controllers:Api:UserController → [Monitor:Http:Controllers:Api:UserController]
```

### Controlled Execution Blocks

[](#controlled-execution-blocks)

**What it does:** Monitors critical operations with automatic start/end logging, exception-specific handling, DB transactions, circuit breakers, and true escalation for uncaught exceptions.

**Note:** The second parameter `$origin` (usually `$this`) is optional and automatically provides origin context to the structured logger used by the controlled block, eliminating the need for a separate `->log()` call.

#### **Factory &amp; Execution**

[](#factory--execution)

```
use Kirschbaum\Monitor\Facades\Monitor;

// Create and execute controlled block
$result = Monitor::controlled('payment_processing', $this)
    ->run(function() {
        return processPayment($data);
    });
```

#### **Context Management**

[](#context-management)

```
/*
 * Adds additional context to the structured logger.
 */
Monitor::controlled('payment_processing', $this)
    ->addContext([
        'transaction_id' => 'txn_456',
        'gateway' => 'stripe'
    ]);

/*
 * Will completely replace structured logger context.
 * ⚠️ Not recommended unless you have a good reason to do so.
 */
Monitor::controlled('payment_processing', $this)
    ->overrideContext([
        'user_id' => 123,
        'operation' => 'payment',
        'amount' => 99.99
    ]);
```

#### **Exception Handling**

[](#exception-handling)

**Exception-Specific Handlers (`catching`):**

```
Monitor::controlled('payment_processing', $this)
    ->catching([
        DatabaseException::class => function($exception, $meta) {
            $cachedData = ExampleModel::getCachedData();
            return $cachedData; // Recovery value
        },
        NetworkException::class => function($exception, $meta) {
            $this->exampleRetryLater($meta);
            // No return = just handle, don't recover
        },
        PaymentException::class => function($exception, $meta) {
            $this->exampleNotifyFinanceTeam($exception, $meta);
            throw $exception; // Re-throw if needed
        },
        // Other exception types remain uncaught.
    ])
```

**Uncaught Exception Handling (`onUncaughtException`):**

```
Monitor::controlled('payment_processing', $this)
    ->onUncaughtException(function($exception, $meta) {
        // Example actions, the exception will remain uncaught
        $this->alertOpsTeam($exception, $meta);
        $this->sendToErrorTracking($exception);
    })
```

**Key Behavior:**

- Only specified exception types in `catching()` are handled
- Handlers can return recovery values to prevent re-throwing
- `onUncaughtException()` **only** fires for exceptions not caught by `catching()` handlers
- True separation between expected (caught) and unexpected (uncaught) failures

#### **Circuit Breaker &amp; Database Protection**

[](#circuit-breaker--database-protection)

**What are Circuit Breakers?**Circuit breakers prevent cascading failures by temporarily stopping requests to a failing service, allowing it time to recover. They automatically "open" after a threshold of failures and "close" once the service is healthy again, protecting your application from wasting resources on operations likely to fail.

```
Monitor::controlled('payment_processing', $this)
    ->withCircuitBreaker('payment_gateway', 3, 60) // 3 failures, 60s timeout
    ->withDatabaseTransaction(2, [DeadlockException::class], [ValidationException::class])
```

**Circuit Breaker HTTP Middleware**

You can also protect entire routes or route groups using the `CheckCircuitBreakers` middleware:

```
// bootstrap/app.php or register as route middleware
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'circuit' => \Kirschbaum\Monitor\Http\Middleware\CheckCircuitBreakers::class,
    ]);
})

// In your routes
Route::middleware(['circuit:payment_gateway,external_api'])
    ->group(function () {
        Route::post('/payments', [PaymentController::class, 'store']);
        Route::get('/external-data', [DataController::class, 'fetch']);
    });

// Or on individual routes
Route::get('/api/data')
    ->middleware('circuit:slow_service')
    ->name('data.fetch');
```

**Circuit Breaker Middleware Features:**

- **Multiple Breakers**: Check multiple circuit breakers with `circuit:breaker1,breaker2,breaker3`
- **Graceful Degradation**: Returns HTTP 503 (Service Unavailable) when circuit is open
- **Standard Headers**: Includes `Retry-After`, `X-Circuit-Breaker`, and `X-Circuit-Breaker-Status` headers
- **Jitter Protection**: Built-in randomized retry delays prevent thundering herd effects
- **Auto-Recovery**: Circuits automatically close when services recover

**Response Headers When Circuit is Open:**

```
HTTP/1.1 503 Service Unavailable
Retry-After: 45
X-Circuit-Breaker: payment_gateway
X-Circuit-Breaker-Status: open

```

The `Retry-After` header includes intelligent jitter - instead of all clients retrying at the exact same time, it provides a random delay between 0 and the remaining decay time, preventing overwhelming the recovering service.

#### **Tracing &amp; Logging**

[](#tracing--logging)

```
Monitor::controlled('payment_processing', $this)
    ->overrideTraceId('custom-trace-12345')
    // Origin is automatically set from the second parameter ($this)
```

#### **Complete Example**

[](#complete-example)

```
class PaymentService
{
    public function processPayment($amount, $userId)
    {
        return Monitor::controlled('payment_processing', $this)
            ->addContext([
                'user_id' => $userId,
                'amount' => $amount,
                'currency' => 'USD'
            ])
            ->withCircuitBreaker('payment_gateway', 3, 120)
            ->withDatabaseTransaction(1, [DeadlockException::class])
            ->catching([
                PaymentDeclinedException::class => function($e, $meta) {
                    return ['status' => 'declined', 'reason' => $e->getMessage()];
                },
                InsufficientFundsException::class => function($e, $meta) {
                    return ['status' => 'insufficient_funds'];
                }
            ])
            ->onUncaughtException(fn($e, $meta) => SomeEscalationLogic::run($e, $meta))
            ->run(function() use ($amount) {
                return $this->chargeCard($amount);
            });
    }
}
```

#### **What it logs:**

[](#what-it-logs)

**Success:**

```
{"message": "[Monitor:Services:PaymentService] STARTED", "controlled_block": "payment_processing", "controlled_block_id": "01HK..."}
{"message": "[Monitor:Services:PaymentService] ENDED", "status": "ok", "duration_ms": 1250}
```

**Caught Exception (Recovery):**

```
{"message": "[Monitor:Services:PaymentService] STARTED", "controlled_block": "payment_processing"}
{"message": "[Monitor:Services:PaymentService] CAUGHT", "exception": "PaymentDeclinedException", "duration_ms": 500}
{"message": "[Monitor:Services:PaymentService] RECOVERED", "recovery_value": "array"}
```

**Uncaught Exception (Escalation):**

```
{"message": "[Monitor:Services:PaymentService] STARTED", "controlled_block": "payment_processing"}
{"message": "[Monitor:Services:PaymentService] UNCAUGHT", "exception": "RuntimeException", "uncaught": true, "duration_ms": 300}
```

#### **API Reference**

[](#api-reference)

MethodPurposeReturns`Monitor::controlled(string $name, string|object $origin = null)`Create controlled block with optional origin`self``->overrideContext(array $context)`Replace entire context`self``->addContext(array $context)`Merge additional context`self``->catching(array $handlers)`Define exception-specific handlers`self``->onUncaughtException(Closure $callback)`Handle uncaught exceptions only`self``->withCircuitBreaker(string $name, int $threshold, int $decay)`Configure circuit breaker`self``->withDatabaseTransaction(int $retries, array $only, array $exclude)`Wrap in DB transaction with retry`self``->overrideTraceId(string $traceId)`Set custom trace ID`self``->run(Closure $callback)`Execute the controlled block`mixed`### Distributed Tracing

[](#distributed-tracing)

**What it does:** Provides correlation IDs that follow requests across services, jobs, and operations.

```
use Kirschbaum\Monitor\Facades\Monitor;

class OrderController extends Controller
{
    public function store()
    {
        // Start trace (typically via middleware)
        Monitor::trace()->start();

        Monitor::log($this)->info('Processing order');

        // All subsequent operations share the same trace ID
        $this->paymentService->charge($amount);

        // Queue job with trace context
        ProcessOrderJob::dispatch($order);
    }
}

class PaymentService
{
    public function charge($amount)
    {
        // Automatically includes trace ID from OrderController
        Monitor::log($this)->info('Charging card', ['amount' => $amount]);
    }
}
```

**Trace Management:**

```
// Manual control
Monitor::trace()->start();            // Generate new UUID (throws if already started)
Monitor::trace()->override($traceId); // Use specific ID (overwrites existing)
Monitor::trace()->pickup($traceId);   // Start if not started, optionally with specific ID
Monitor::trace()->id();               // Get current ID (throws if not started)
Monitor::trace()->hasStarted();       // Check if active
Monitor::trace()->hasNotStarted();    // Check if not active
```

**Key Differences:**

- `start()` - Throws exception if trace already exists
- `override()` - Always sets trace ID, replacing any existing one
- `pickup()` - Safe method that starts only if not already started

### HTTP Middleware

[](#http-middleware)

**What it does:** Automatically manages trace IDs for HTTP requests, enabling seamless distributed tracing across services.

**Registration:**

```
// bootstrap/app.php
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\Kirschbaum\Monitor\Http\Middleware\StartMonitorTrace::class);
})
```

**Behavior:**

- **Incoming:** Picks up `X-Trace-Id` header or generates new UUID
- **Outgoing:** Sets `X-Trace-Id` header in response
- **Preserves:** Existing traces when already started

**Cross-service usage:**

```
// Service A
$response = Http::withHeaders([
    'X-Trace-Id' => Monitor::trace()->id()
])->get('https://service-b.example.com/api/data');

// Service B automatically uses the same trace ID
```

**Configuration:** Custom header name via `trace_header` config or `MONITOR_TRACE_HEADER` env var.

### Performance Timing

[](#performance-timing)

**What it does:** Provides millisecond-precision timing for operations.

```
use Kirschbaum\Monitor\Facades\Monitor;

class DataProcessor
{
    public function processData()
    {
        $timer = Monitor::time(); // Auto-starts

        // Your processing code
        $this->heavyOperation();

        $elapsed = $timer->elapsed(); // Milliseconds

        Monitor::log($this)->info('Processing complete', [
            'duration_ms' => $elapsed
        ]);
    }
}
```

**Note:** All Monitor logging automatically includes `duration_ms` from service start.

### Circuit Breaker Direct Access

[](#circuit-breaker-direct-access)

**What it does:** Provides direct access to circuit breaker state management for advanced use cases.

```
use Kirschbaum\Monitor\Facades\Monitor;

// Check circuit breaker state
$isOpen = Monitor::breaker()->isOpen('payment_gateway');
$state = Monitor::breaker()->getState('payment_gateway');

// Manual state management
Monitor::breaker()->recordFailure('api_service', 300); // Record failure with 300s decay
Monitor::breaker()->recordSuccess('api_service');      // Record success (resets failures)
Monitor::breaker()->reset('api_service');              // Force reset
Monitor::breaker()->forceOpen('api_service');          // Force open state
```

**Usage in Custom Logic:**

```
class ExternalApiService
{
    public function makeRequest()
    {
        if (Monitor::breaker()->isOpen('external_api')) {
            return $this->getCachedResponse();
        }

        try {
            $response = $this->performApiCall();
            Monitor::breaker()->recordSuccess('external_api');
            return $response;
        } catch (Exception $e) {
            Monitor::breaker()->recordFailure('external_api', 120);
            throw $e;
        }
    }
}
```

### Log Redactor Direct Access

[](#log-redactor-direct-access)

**What it does:** Provides direct access to the redactor for custom redaction needs.

```
use Kirschbaum\Monitor\Facades\Monitor;

// Direct redaction using configured profile
$redactedData = Monitor::redactor()->redact($sensitiveData);

// Custom profile redaction
$redactedData = Monitor::redactor()->redact($sensitiveData, 'strict');

// Example usage
class UserDataProcessor
{
    public function processUserData(array $userData)
    {
        // Redact before logging or storing
        $safeData = Monitor::redactor()->redact($userData);

        Monitor::log($this)->info('Processing user data', $safeData);

        return $this->process($userData); // Use original for processing
    }
}
```

### Log Redaction

[](#log-redaction)

**What it does:** Automatically scrubs sensitive data from log context using [Kirschbaum Redactor](https://github.com/kirschbaum-development/redactor) to ensure compliance and security while preserving important data.

**Configuration:** Simple redaction configuration in `config/monitor.php`:

```
'redactor' => [
    'enabled' => true,
    'redactor_profile' => 'default', // Uses Kirschbaum Redactor profiles
],
```

**Usage:** Redaction is automatically applied to all Monitor log context:

```
Monitor::log($this)->info('User data', [
    'id' => 123,
    'email' => 'user@example.com',    // → '[REDACTED]' based on profile rules
    'password' => 'secret123',        // → '[REDACTED]' based on profile rules
    'api_token' => 'sk-1234567890abcdef...', // → '[REDACTED]' based on profile rules
    'name' => 'John Doe',             // → 'John Doe' (if allowed by profile)
]);
```

For detailed redaction configuration, rules, patterns, and profiles, see the [Kirschbaum Redactor documentation](https://github.com/kirschbaum-development/redactor).

Complete API Reference
----------------------

[](#complete-api-reference)

The Monitor facade provides access to all monitoring components:

```
use Kirschbaum\Monitor\Facades\Monitor;

// Structured logging
Monitor::log($origin)->info('message', $context);

// Controlled execution blocks
Monitor::controlled($name, $origin)->run($callback);

// Distributed tracing
Monitor::trace()->start();
Monitor::trace()->pickup($traceId);

// Performance timing
Monitor::time()->elapsed();

// Circuit breaker management
Monitor::breaker()->isOpen($name);

// Log redaction
Monitor::redactor()->redact($data);
```

All components integrate seamlessly and share trace context automatically when used together.

Configuration
-------------

[](#configuration)

**Environment Variables:**

```
# Core settings
MONITOR_ENABLED=true

# Exception tracing (applies to Controlled blocks only)
MONITOR_TRACE_ENABLED=true
MONITOR_TRACE_FULL_ON_DEBUG=true
MONITOR_TRACE_FORCE_FULL_TRACE=false
MONITOR_TRACE_MAX_LINES=15

# Auto-trace console commands
MONITOR_CONSOLE_AUTO_TRACE_ENABLED=true
MONITOR_CONSOLE_AUTO_TRACE_ENABLE_IN_TESTING=false

# HTTP trace header
MONITOR_TRACE_HEADER=X-Trace-Id

# Circuit breaker defaults
MONITOR_CIRCUIT_BREAKER_DECAY_SECONDS=300
MONITOR_CIRCUIT_BREAKER_RETRY_AFTER=300
MONITOR_CIRCUIT_BREAKER_CORS_HEADERS=false

# Log redaction
MONITOR_REDACTOR_ENABLED=true
MONITOR_REDACTOR_PROFILE=default
```

**Logging Channel:** Configure a dedicated Monitor logging channel:

```
// config/logging.php
'channels' => [
    'monitor' => [
        'driver' => 'daily',
        'path' => storage_path('logs/monitor.log'),
        'level' => 'debug',
        'days' => 14,
        'tap' => [
            \Kirschbaum\Monitor\Taps\StructuredLoggingTap::class,
        ],
    ],
],
```

Output Examples
---------------

[](#output-examples)

**Structured Log Entry:**

```
{
    "level": "info",
    "event": "Monitor:Http:Controllers:UserController:info",
    "message": "[Monitor:Http:Controllers:UserController] User login successful",
    "trace_id": "9d2b4e8f-3a1c-4d5e-8f2a-1b3c4d5e6f7g",
    "context": {
        "user_id": 123,
        "ip_address": "192.168.1.1",
        "_redacted": true
    },
    "timestamp": "2024-01-15T14:30:45.123Z",
    "duration_ms": 1245,
    "memory_mb": 45.23
}
```

**Controlled Block Execution:**

```
{"message": "[Monitor:Services:PaymentService] STARTED", "controlled_block": "payment_processing", "controlled_block_id": "01HK4...", "trace_id": "9d2b4e8f..."}
{"message": "[Monitor:Services:PaymentService] ENDED", "controlled_block": "payment_processing", "status": "ok", "duration_ms": 1250}
```

**Failure with Exception:**

```
{
    "message": "[Monitor:Services:PaymentService] UNCAUGHT",
    "controlled_block": "payment_processing",
    "exception": {
        "class": "RuntimeException",
        "message": "Card declined",
        "file": "/app/PaymentService.php",
        "line": 45,
        "trace": ["...", "..."]
    },
    "duration_ms": 500,
    "uncaught": true
}
```

Testing
-------

[](#testing)

Run the test suite:

```
vendor/bin/pest
```

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE) for more information.

###  Health Score

37

—

LowBetter than 81% of packages

Maintenance61

Regular maintenance activity

Popularity18

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity50

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~7 days

Total

4

Last Release

360d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/57e405b52d482c9de35b17f299d2745e8e68d9d9951aec64854f2d7fa53110bf?d=identicon)[luisdalmolin](/maintainers/luisdalmolin)

---

Top Contributors

[![belisarh](https://avatars.githubusercontent.com/u/11684453?v=4)](https://github.com/belisarh "belisarh (5 commits)")

---

Tags

laravelloggingtracemonitortelemetryobservabilitycontrolled

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/kirschbaum-development-monitor/health.svg)

```
[![Health](https://phpackages.com/badges/kirschbaum-development-monitor/health.svg)](https://phpackages.com/packages/kirschbaum-development-monitor)
```

###  Alternatives

[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M164](/packages/spatie-laravel-health)[defstudio/telegraph

A laravel facade to interact with Telegram Bots

816333.6k3](/packages/defstudio-telegraph)[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

167558.4k1](/packages/keepsuit-laravel-opentelemetry)[harris21/laravel-fuse

Circuit breaker for Laravel queue jobs. Protect your workers from cascading failures.

44855.7k](/packages/harris21-laravel-fuse)[simplestats-io/laravel-client

Server-side analytics for Laravel that follows the full funnel from visit to registration to payment, attributed to the channel that drove it. Revenue, MRR, churn and ad-spend profit (ROAS/CAC) per channel. GDPR compliant, ad-blocker proof.

5021.9k](/packages/simplestats-io-laravel-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
