PHPackages                             modus-digital/laravel-monitoring - 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. modus-digital/laravel-monitoring

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

modus-digital/laravel-monitoring
================================

OTLP-first observability for Laravel — traces, logs, and metrics via Grafana Alloy.

1.3.0(2mo ago)1125↓92.3%MITPHPPHP ^8.4CI passing

Since Apr 2Pushed 2mo agoCompare

[ Source](https://github.com/modus-digital/laravel-monitoring)[ Packagist](https://packagist.org/packages/modus-digital/laravel-monitoring)[ Docs](https://github.com/modus-digital/laravel-monitoring)[ GitHub Sponsors]()[ RSS](/packages/modus-digital-laravel-monitoring/feed)WikiDiscussions main Synced today

READMEChangelog (6)Dependencies (23)Versions (11)Used By (0)

Laravel Monitoring
==================

[](#laravel-monitoring)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f0e5bb1cb62462dbb0dc34f25b39f998f08e123f9e9ce01a2cb729e737ffa251/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d6f6475732d6469676974616c2f6c61726176656c2d6d6f6e69746f72696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/modus-digital/laravel-monitoring)[![GitHub Tests Action Status](https://camo.githubusercontent.com/8199e6c366107370d91b3d4a405872c126c77eae034332894e8ec2c8a62cceb8/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6f6475732d6469676974616c2f6c61726176656c2d6d6f6e69746f72696e672f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/modus-digital/laravel-monitoring/actions?query=workflow%3Arun-tests+branch%3Amain)[![GitHub Code Style Action Status](https://camo.githubusercontent.com/261ead5e7d797e08da4dc6b49e5d7e7bfc01d7f0937c1399b0f5e7c8ab364615/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6d6f6475732d6469676974616c2f6c61726176656c2d6d6f6e69746f72696e672f6669782d7068702d636f64652d7374796c652d6973737565732e796d6c3f6272616e63683d6d61696e266c6162656c3d636f64652532307374796c65267374796c653d666c61742d737175617265)](https://github.com/modus-digital/laravel-monitoring/actions?query=workflow%3A%22Fix+PHP+code+style+issues%22+branch%3Amain)[![Total Downloads](https://camo.githubusercontent.com/017b9f207530d6e18c0b2a648077d98ce23b6d5e079820c38f16109d39045a66/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6d6f6475732d6469676974616c2f6c61726176656c2d6d6f6e69746f72696e672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/modus-digital/laravel-monitoring)

OTLP-first observability for Laravel — traces, logs, and metrics via Grafana Alloy.

- Distributed tracing with W3C `traceparent` propagation
- Auto-instrumentation for DB queries, HTTP client, cache, and queue jobs
- HTTP request metrics (counter + histogram) for Grafana dashboards
- OTLP log shipping as a native Laravel log channel
- Custom counters, gauges, and histograms
- Exception reporting on active spans
- All telemetry exported as OTLP/JSON to Grafana Alloy (or any OTLP-compatible collector)
- No scheduler, no cron — everything flushes per-request automatically

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 12 or 13
- An OTLP-compatible collector (e.g., [Grafana Alloy](https://grafana.com/docs/alloy/))

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

[](#installation)

```
composer require modus-digital/laravel-monitoring
```

Publish the config file:

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

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

[](#configuration)

Add these to your `.env`:

```
MONITORING_ENABLED=true
MONITORING_OTLP_ENDPOINT=http://alloy:4318
MONITORING_SERVICE_NAME=my-app
MONITORING_ENVIRONMENT=production
```

### Full config reference

[](#full-config-reference)

```
// config/monitoring.php
return [
    'enabled' => env('MONITORING_ENABLED', true),

    'service' => [
        'name'        => env('MONITORING_SERVICE_NAME'),        // defaults to config('app.name')
        'environment' => env('MONITORING_ENVIRONMENT'),          // defaults to config('app.env')
        'instance_id' => env('MONITORING_SERVICE_INSTANCE_ID'),  // defaults to config('app.url')
    ],

    'otlp' => [
        'endpoint' => env('MONITORING_OTLP_ENDPOINT', 'http://127.0.0.1:4318'),
        'headers'  => env('MONITORING_OTLP_HEADERS'),  // comma-separated: 'X-Scope-OrgID=tenant1,Authorization=Basic abc'
        'timeout'  => env('MONITORING_OTLP_TIMEOUT', 3),
    ],

    'traces' => [
        'enabled'     => env('MONITORING_TRACES_ENABLED', true),
        'sample_rate' => env('MONITORING_TRACE_SAMPLE_RATE', 1.0),  // 0.0 to 1.0
    ],

    'logs' => [
        'enabled' => env('MONITORING_LOGS_ENABLED', true),
    ],

    'metrics' => [
        'enabled' => env('MONITORING_METRICS_ENABLED', true),
    ],

    // Routes to exclude from tracing. Matches against both route names and URL paths.
    'middleware' => [
        'exclude' => [],
    ],

    // Auto-instrumentation creates child spans for these operations.
    'auto_instrumentation' => [
        'db'          => env('MONITORING_INSTRUMENT_DB', true),
        'http_client' => env('MONITORING_INSTRUMENT_HTTP_CLIENT', true),
        'cache'       => env('MONITORING_INSTRUMENT_CACHE', true),
        'queue'       => env('MONITORING_INSTRUMENT_QUEUE', true),
    ],
];
```

Middleware Setup
----------------

[](#middleware-setup)

Register the `StartRequestTrace` middleware to automatically trace HTTP requests:

```
// bootstrap/app.php (Laravel 12+)
->withMiddleware(function (Middleware $middleware) {
    $middleware->append(\ModusDigital\LaravelMonitoring\Http\Middleware\StartRequestTrace::class);
})
```

This middleware:

- Creates a root span for each HTTP request with `SERVER` kind
- Records `http_requests_total` counter and `http_request_duration_ms` histogram (even when tracing is unsampled)
- Parses incoming `traceparent` headers for distributed trace propagation
- Records `http.method`, `http.route`, `http.status_code`, and `http.status_group` attributes
- Sets `ERROR` status on 5xx responses
- Populates a `RequestContext` singleton for log correlation
- Respects the `traces.sample_rate` config and upstream sampling decisions
- Flushes all telemetry inline (after the response is sent)

Usage
-----

[](#usage)

### Tracing

[](#tracing)

Wrap operations in spans using the `Monitoring` facade:

```
use ModusDigital\LaravelMonitoring\Facades\Monitoring;

// Automatic span — wraps a closure, records exceptions, rethrows
$result = Monitoring::span('orders.process', function () {
    return Order::process($data);
});

// Manual span — for more control
$span = Monitoring::startSpan('external.api.call');
$span->setAttribute('api.endpoint', 'https://api.example.com/v1/users');
try {
    $response = Http::get('https://api.example.com/v1/users');
    $span->setAttribute('http.status_code', $response->status());
} finally {
    $span->end();
}
```

### Auto-Instrumentation

[](#auto-instrumentation)

The package automatically creates child spans for common Laravel operations. Each can be toggled via config or env vars.

**Database queries** — `db.query` spans with SQL, driver, duration, and connection name:

```
MONITORING_INSTRUMENT_DB=true
```

**HTTP client calls** — `http.client` spans with method, URL, and status code. Sets `ERROR` status on 5xx responses:

```
MONITORING_INSTRUMENT_HTTP_CLIENT=true
```

**Cache operations** — `cache.hit`, `cache.miss`, `cache.write`, `cache.forget` spans with key and store:

```
MONITORING_INSTRUMENT_CACHE=true
```

**Queue jobs** — `queue.job` spans with job class, queue, connection, and attempt. Records exception events on failure:

```
MONITORING_INSTRUMENT_QUEUE=true
```

All auto-instrumentation requires an active parent span (created by the middleware). When a request is unsampled, listeners are no-ops.

### Exception Handling

[](#exception-handling)

Report exceptions on the active trace span using the `Monitoring` facade:

```
// bootstrap/app.php
->withExceptions(function (Exceptions $exceptions) {
    $exceptions->reportable(function (Throwable $e) {
        \ModusDigital\LaravelMonitoring\Facades\Monitoring::reportException($e);
    });
})
```

This records an `exception` event on the active span with `exception.type`, `exception.message`, and `exception.stacktrace`, and sets the span status to `ERROR`. Safe to call when no active span exists (no-op).

### Custom Metrics

[](#custom-metrics)

Use the `Monitoring` facade or the `monitoring()` helper:

#### Counters

[](#counters)

Counters only go up. Use them for totals (requests, orders, errors).

```
Monitoring::counter('orders_total', ['payment_method' => 'stripe'])->increment();
Monitoring::counter('orders_total', ['payment_method' => 'stripe'])->incrementBy(5);

// Or via the helper
monitoring()->counter('orders_total')->increment();
```

#### Gauges

[](#gauges)

Gauges go up and down. Use them for current values (queue depth, active users).

```
Monitoring::gauge('queue_depth', ['queue' => 'emails'])->set(42);
Monitoring::gauge('queue_depth', ['queue' => 'emails'])->increment();
Monitoring::gauge('queue_depth', ['queue' => 'emails'])->decrement();
```

#### Histograms

[](#histograms)

Histograms observe values into configurable buckets. Use them for durations, sizes, etc.

```
Monitoring::histogram('response_time_ms', ['endpoint' => '/api/users'])->observe(123.5);

// Custom buckets (default: 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000)
Monitoring::histogram('payload_size_bytes', [], [100, 500, 1000, 5000, 10000])->observe(2048);
```

### Labels

[](#labels)

All metric types accept an optional labels array. Label order doesn't matter — `['a' => '1', 'b' => '2']` and `['b' => '2', 'a' => '1']` resolve to the same metric.

### Flushing

[](#flushing)

Telemetry is flushed automatically:

- **Traces and logs**: Flushed on `terminate()` after each HTTP response
- **Metrics in queue jobs**: Flushed automatically via `Queue::after` and `Queue::failing` hooks
- **Manual flush**: Call `Monitoring::flush()` to export all pending traces and metrics

No scheduler or cron job is needed.

Log Shipping
------------

[](#log-shipping)

The package registers a `monitoring` log channel automatically. Add it to your logging stack:

```
// config/logging.php
'channels' => [
    'stack' => [
        'driver' => 'stack',
        'channels' => ['daily', 'monitoring'],
    ],
],
```

Log records are automatically enriched with trace context (`trace_id`, `span_id`, `request_id`, `route`, `method`, `user_id`) so you can correlate logs with traces in Grafana.

How It Works
------------

[](#how-it-works)

1. The `StartRequestTrace` middleware creates a root span, records HTTP metrics, and populates `RequestContext`
2. Auto-instrumentation listeners create child spans for DB queries, HTTP client calls, cache operations, and queue jobs
3. Your app records custom spans and metrics via the `Monitoring` facade
4. The `MonitoringLogProcessor` enriches log records with trace context
5. The middleware ends the root span, flushes traces via OTLP/JSON to `/v1/traces`, and exports metrics to `/v1/metrics`
6. The `OtlpLogHandler` buffers log records and flushes them to `/v1/logs` on close
7. All in-memory, no cache driver or external state needed

All OTLP payloads include resource attributes (`service.name`, `deployment.environment`, `service.instance.id`) for identification in Grafana.

Architecture
------------

[](#architecture)

```
Laravel App
  ├── StartRequestTrace (middleware)
  │     ├── Creates root Span (SERVER kind)
  │     ├── Records http_requests_total + http_request_duration_ms metrics
  │     ├── Populates RequestContext
  │     └── Flushes traces + metrics inline
  ├── Auto-Instrumentation (event listeners)
  │     ├── TraceDbQueries       → db.query child spans
  │     ├── TraceHttpClient      → http.client child spans
  │     ├── TraceCacheOperations → cache.hit/miss/write/forget child spans
  │     └── TraceQueueJobs       → queue.job root spans
  ├── Monitoring Facade
  │     ├── span() / startSpan()  → TracerContract → OtlpTracer
  │     ├── reportException()     → records exception on active span
  │     ├── counter() / gauge() / histogram()  → MetricRegistry
  │     └── flush()  → exports traces + metrics
  ├── Log Channel ("monitoring")
  │     ├── MonitoringLogProcessor (enriches with trace context)
  │     └── OtlpLogHandler → OtlpLogExporter
  └── OtlpTransport (shared HTTP/JSON client)
        ├── POST /v1/traces   (traces)
        ├── POST /v1/logs     (logs)
        └── POST /v1/metrics  (metrics)
              ↓
        Grafana Alloy → Tempo / Loki / Mimir

```

Testing
-------

[](#testing)

```
composer test              # Run tests (Pest)
composer test-coverage     # Tests with coverage
composer analyse           # PHPStan level 8
composer format            # Laravel Pint code style
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Credits
-------

[](#credits)

- [Alex van Steenhoven](https://github.com/modus-digital)
- [All Contributors](../../contributors)

License
-------

[](#license)

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

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance85

Actively maintained with recent releases

Popularity11

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 96.2% 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 ~1 days

Total

6

Last Release

87d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/67007082?v=4)[Alex van Steenhoven](/maintainers/AlexVanSteenhoven)[@AlexVanSteenhoven](https://github.com/AlexVanSteenhoven)

---

Top Contributors

[![AlexVanSteenhoven](https://avatars.githubusercontent.com/u/67007082?v=4)](https://github.com/AlexVanSteenhoven "AlexVanSteenhoven (75 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (2 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravellaravel-monitoringModus Digital

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/modus-digital-laravel-monitoring/health.svg)

```
[![Health](https://phpackages.com/badges/modus-digital-laravel-monitoring/health.svg)](https://phpackages.com/packages/modus-digital-laravel-monitoring)
```

###  Alternatives

[spatie/laravel-permission

Permission handling for Laravel 12 and up

12.9k102.4M1.4k](/packages/spatie-laravel-permission)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M47](/packages/spatie-laravel-pdf)[spatie/laravel-health

Monitor the health of a Laravel application

87512.0M164](/packages/spatie-laravel-health)[dedoc/scramble

Automatic generation of API documentation for Laravel applications.

2.1k11.2M100](/packages/dedoc-scramble)[spatie/laravel-passkeys

Use passkeys in your Laravel app

471890.7k39](/packages/spatie-laravel-passkeys)[keepsuit/laravel-opentelemetry

OpenTelemetry integration for laravel

167558.4k1](/packages/keepsuit-laravel-opentelemetry)

PHPackages © 2026

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