PHPackages                             nightowl/agent - 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. nightowl/agent

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

nightowl/agent
==============

NightOwl monitoring agent — collects telemetry from laravel/nightwatch and writes to PostgreSQL

v2.0.1(1w ago)915.8k8MITPHPPHP ^8.2CI passing

Since Mar 30Pushed 1w ago3 watchersCompare

[ Source](https://github.com/lemed99/nightowl-agent)[ Packagist](https://packagist.org/packages/nightowl/agent)[ Fund](https://buy.polar.sh/polar_cl_K2ykmjbHPVEaOBpuU4FtomEg5yGMBp4W2Tcxf0ob7Cm)[ RSS](/packages/nightowl-agent/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (51)Versions (65)Used By (0)

 [![NightOwl](.github/assets/logo.svg)](.github/assets/logo.svg)

NightOwl Agent
==============

[](#nightowl-agent)

 **Open-source Laravel monitoring agent. Captures telemetry from [`laravel/nightwatch`](https://github.com/laravel/nightwatch) and drains it into a PostgreSQL database you control.**

 [![Packagist Version](https://camo.githubusercontent.com/473e7fa6579e2336f6a975915ee4be8360a55c3cd04b19f866018eaa519a59db/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6e696768746f776c2f6167656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nightowl/agent) [![PHP 8.2+](https://camo.githubusercontent.com/36f43f80df056872e314cbb084b77cf0d8d6625e842c12b25db6a56bb90c8b96/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f7068702d762f6e696768746f776c2f6167656e742e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/nightowl/agent) [![MIT License](https://camo.githubusercontent.com/5f49060d51dd5b2e81c0b338bb22877a3b0728a91333fe4afec08ffbea71f64a/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6c656d656439392f6e696768746f776c2d6167656e742e7376673f7374796c653d666c61742d737175617265)](LICENSE) [![Tests](https://camo.githubusercontent.com/8cbbfde7646cf09b1e198770cb7758e6e96faf1cd361f2931b44a98c744a1a9b/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f6c656d656439392f6e696768746f776c2d6167656e742f74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/lemed99/nightowl-agent/actions/workflows/tests.yml)

---

What is this?
-------------

[](#what-is-this)

NightOwl Agent is an MIT-licensed Laravel package that:

1. **Sits in front of [`laravel/nightwatch`](https://github.com/laravel/nightwatch)** — Laravel's official observability SDK. Nightwatch already does the hard part: instrumenting all 12 record types — requests, queries, jobs, exceptions, commands, cache events, mail, notifications, outgoing HTTP, scheduled tasks, logs, users. The agent receives those payloads over a local TCP socket.
2. **Buffers them in a local SQLite WAL** — non-blocking ReactPHP ingest, ~13,400 payloads/s on a single instance.
3. **Drains them into a PostgreSQL database you provision** via the COPY protocol. Telemetry never leaves your network.

All tables are prefixed `nightowl_` and the schema is documented. You're free to query the data with `psql`, point Metabase at it, or build your own UI on top — Livewire, Next.js, whatever.

Run it standalone
-----------------

[](#run-it-standalone)

This package is fully usable on its own. Point it at a PostgreSQL database you control and you have a self-hosted Laravel APM:

```
composer require nightowl/agent
php artisan nightowl:install        # publishes config + runs migrations against your PG
php artisan nightowl:agent          # starts the TCP/UDP/health daemon (ports 2407/2408/2409)
```

Minimal `.env` (PostgreSQL credentials — that's it):

```
NIGHTOWL_DB_HOST=127.0.0.1
NIGHTOWL_DB_PORT=5432
NIGHTOWL_DB_DATABASE=nightowl
NIGHTOWL_DB_USERNAME=nightowl
NIGHTOWL_DB_PASSWORD=nightowl
NIGHTOWL_DB_SSLMODE=prefer
```

You don't need to wire up Nightwatch's transport — the service provider automatically redirects its ingest to the local agent on `127.0.0.1:2407`. For a local-only setup you also don't need any token; the agent only enforces one if you set `NIGHTOWL_TOKEN` (useful when the agent listens on something other than loopback).

Tables fill up. Run any SQL you want against them.

Updating
--------

[](#updating)

```
composer update nightowl/agent
# then restart the agent however you already restart it
```

The migrate step happens on boot: when the agent starts and its schema is behind, it applies the pending migrations itself before it accepts traffic, so schema changes arrive with the code that needs them. That schema run is bounded by `NIGHTOWL_AUTO_MIGRATE_TIMEOUT` (300s) and executes in a child process the agent kills at the deadline — a lock on your database can never leave the ingest port unbound. If it doesn't finish, the agent starts anyway on the old schema and retries next boot. Long rollup backfills continue in a detached background process (log: `storage/logs/nightowl-boot-migrate.log`) and are retried on a later boot if one dies partway.

**The agent does not restart itself.** A running process keeps the code it booted with, so until you restart it the update isn't live. To make that visible rather than silent, the daemon checks `vendor/composer/installed.php` every few minutes and logs a warning once it sees a newer version on disk than the one it's running:

```
[NightOwl Agent] Update available: a newer nightowl/agent is installed on disk
(v2.0.0#… -> v2.1.0#…) but this process is still running the old one. Restart
the agent to pick it up …

```

Restarting is deliberately left to you: whether a supervisor would bring the agent back after a self-initiated exit depends on configuration the agent can't verify, and being wrong about that leaves you with no agent at all rather than a slightly stale one.

Running `nightowl:migrate` in your deploy pipeline is still worthwhile — the boot-time run is the safety net, and a pipeline run does the rollup backfill where its latency is visible.

Opt out with `NIGHTOWL_AUTO_MIGRATE=false` (e.g. a DB role without DDL rights) or `NIGHTOWL_UPDATE_CHECK=false`.

Disabling NightOwl
------------------

[](#disabling-nightowl)

Set `NIGHTOWL_ENABLED=false` to make the package fully inert — the Nightwatch ingest hook is not wired (no telemetry is collected or transmitted) and the migrations are not registered. The most common use is turning it off in your test suite so tests don't pay the ingest overhead or require the `nightowl` database to exist:

```

```

`nightowl:install` runs its migrations regardless of this flag (it's an explicit opt-in), so you can still install while the switch is off.

Sharing one database across environments
----------------------------------------

[](#sharing-one-database-across-environments)

NightOwl stamps an `environment` column (your `APP_ENV`) on every row, so several app environments (local, staging, production) can point at one NightOwl database and be filtered apart in the dashboard. The data is partitioned by environment; the `nightowl_*` tables are shared.

`nightowl:install` and `nightowl:migrate` track their migration history **inside the NightOwl database**, so they're idempotent across environments. Run the schema sync as part of each deploy:

```
php artisan nightowl:migrate
```

The first environment to deploy creates the tables, the rest are no-ops, and upgrades' new migrations apply on whichever environment deploys first. No "owner" environment and no flags. A database that already has the tables but no NightOwl migration history (e.g. created by an older version or by your app's `php artisan migrate`) is adopted as a baseline, so you never hit `relation "nightowl_requests" already exists`.

By default these migrations are **not** bundled into your app's `php artisan migrate`. If you'd rather run them that way (single-database setups only — it tracks history in your primary database and must not be combined with `nightowl:install`), set `NIGHTOWL_RUN_MIGRATIONS=true`.

What you get out of the box
---------------------------

[](#what-you-get-out-of-the-box)

These features run in the agent process. Postgres is the only thing it talks to.

- **Exception fingerprinting** — `nightowl_exceptions` upserts into `nightowl_issues` keyed on `(group_hash, type, environment)`, so repeats roll up into one grouped issue.
- **New-issue alerts** — when an issue is seen for the first time the drain worker fans it out to whatever you've configured in `nightowl_alert_channels`: Email (BYO SMTP), Webhook (HMAC-signed), Slack, Discord.

    Verify that path with:

    ```
    php artisan nightowl:test-alert            # every enabled channel
    php artisan nightowl:test-alert --channel="Ops email"
    ```

    This matters more than it sounds. New-issue and reopened-issue alerts are sent **by the agent, from your server**, over its own SMTP and HTTP. If you use the hosted dashboard, its "Send test" button and its status-change alerts are sent by NightOwl's API from NightOwl's infrastructure. Two different senders reading the same channel row — so a green test in the dashboard does not prove your server can reach your SMTP relay. `nightowl:test-alert` is the one that does, and it prints the actual failure per channel rather than leaving it in the log.

    It ignores each channel's event filter on purpose, so a transport problem can't hide behind one, and tells you afterwards if a channel that passed has new-issue alerts switched off.

    Two SMTP knobs, if your relay is fussy or far away — the credentials themselves stay in the dashboard:

    ```
    NIGHTOWL_SMTP_HELO=mail.example.com   # default: your machine's FQDN, else an address literal
    NIGHTOWL_SMTP_CONNECT_TIMEOUT=10
    NIGHTOWL_SMTP_TIMEOUT=10

    ```
- **Threshold-based performance issues** — set a threshold per record type (slow request, slow query, slow job, and so on), and durations above it get turned into issues.
- **Agent + host health diagnosis** — ring buffers and EWMA feed a rule engine that produces a health score and surfaces stalls (drain lag, buffer depth, CPU, memory, load average).
- **Raw rows for every Nightwatch record type** — all 12 sit in your Postgres. `psql`, Metabase, or your own UI on top.

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

[](#architecture)

```
 Your Laravel app                             Your infrastructure
 ┌──────────────────┐    TCP    ┌──────────────────────────────┐
 │ laravel/         │──2407────▶│ NightOwl Agent (ReactPHP)    │
 │ nightwatch       │           │  ├─ SQLite WAL buffer        │
 └──────────────────┘           │  └─ pcntl drain workers      │
                                │         │                    │
                                │         │ COPY protocol      │
                                │         ▼                    │
                                │   PostgreSQL (yours)         │
                                └────────────┬─────────────────┘
                                             │
                                             ▼
                              ┌─────────────────────────┐
                              │ Your own UI / scripts   │
                              │ (psql, Metabase, vibe-  │
                              │  coded Next.js, etc.)   │
                              └─────────────────────────┘

```

> **13,400 payloads/s** on a single instance — ReactPHP non-blocking TCP ingest, SQLite WAL buffering, PostgreSQL `COPY` drain with `synchronous_commit = off`.

What the agent collects
-----------------------

[](#what-the-agent-collects)

Whatever Nightwatch emits, the agent persists. Each row carries duration (microseconds), `environment`, `deploy`, and the request/job correlation IDs Nightwatch attaches.

- **Requests** — method, route, path, status, duration, memory, user ID
- **Jobs** — queue, attempts, status (queued/processed/released/failed), exception link
- **Queries** — SQL, bindings, connection, duration, request correlation
- **Exceptions** — class, message, stack trace, fingerprint hash (upserted into `nightowl_issues`)
- **Logs** — level, message, context, request correlation
- **Users** — `users_count` upsert (request + exception counters per authenticated user)
- **Cache events, mail, notifications, outgoing HTTP, scheduled tasks, commands** — same shape as Nightwatch
- **Host metrics** — CPU, memory, load average (Linux `/proc`)
- **Agent self-health** — ingest/drain rates, buffer depth, back-pressure, diagnosis rules

P95s, N+1 detection, slow-query rankings, request timelines, etc. are queries you write against these tables.

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

[](#requirements)

- PHP **8.2+** with extensions: `pdo_pgsql`, `pdo_sqlite` (always), `pcntl` + `posix` (for the async driver), `zlib` (for gzipped payloads)
- PostgreSQL **14+** (16 or 17 recommended)
- Laravel **11, 12, 13**

Data ownership &amp; privacy
----------------------------

[](#data-ownership--privacy)

The agent writes telemetry **directly to your PostgreSQL database**. Zero request, query, or exception data leaves your infrastructure.

The only thing the agent *can* send outbound, and only if you opt in to remote health reporting, is **agent/host health metadata** (ingest rates, buffer depth, drain lag, CPU/memory), so a remote backend can warn you when the agent is unhealthy.

The schema is documented and stable, so your data stays usable even if you stop running the agent.

Optional: the hosted dashboard
------------------------------

[](#optional-the-hosted-dashboard)

If you'd rather not build and maintain a UI, [usenightowl.com](https://usenightowl.com) is a managed service that connects to your Postgres with credentials you supply (and can rotate or revoke at any time). It adds an issue lifecycle UI (resolve / ignore / reopen, assignees, comments, activity timeline), alerts for those state transitions, teams, and an MCP server for AI tools. The agent itself stays MIT and works the same with or without it.

Full guide: [docs.usenightowl.com](https://docs.usenightowl.com)

Contributing
------------

[](#contributing)

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, test suite structure, and conventions. Bug reports and feature requests go through [GitHub Issues](https://github.com/lemed99/nightowl-agent/issues).

License
-------

[](#license)

[MIT](LICENSE).

Related
-------

[](#related)

- **Docs** — [docs.usenightowl.com](https://docs.usenightowl.com)

###  Health Score

57

—

FairBetter than 98% of packages

Maintenance98

Actively maintained with recent releases

Popularity41

Moderate usage in the ecosystem

Community12

Small or concentrated contributor base

Maturity61

Established project with proven stability

 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 ~2 days

Total

64

Last Release

8d ago

Major Versions

v0.2.5 → v1.0.02026-05-08

v1.4.1 → v2.0.02026-07-29

### Community

Maintainers

![](https://www.gravatar.com/avatar/102576929b3053fff0a8910dc1e4aedb9ac23bf8780899c12c2488ee56f02b39?d=identicon)[Lemed99](/maintainers/Lemed99)

---

Top Contributors

[![lemed99](https://avatars.githubusercontent.com/u/45576683?v=4)](https://github.com/lemed99 "lemed99 (86 commits)")

---

Tags

apmlaravelmonitoringnightwatchobservabilityphppostgresqlreactphpself-hostedlaravelmonitoringAgenttelemetrynightwatch

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/nightowl-agent/health.svg)

```
[![Health](https://phpackages.com/badges/nightowl-agent/health.svg)](https://phpackages.com/packages/nightowl-agent)
```

###  Alternatives

[friendsofphp/php-cs-fixer

A tool to automatically fix PHP code style

13.5k257.0M27.3k](/packages/friendsofphp-php-cs-fixer)[ccxt/ccxt

A cryptocurrency trading API with more than 100 exchanges in JavaScript / TypeScript / Python / C# / PHP / Go

43.5k344.8k1](/packages/ccxt-ccxt)[team-reflex/discord-php

An unofficial API to interact with the voice and text service Discord.

1.1k434.3k26](/packages/team-reflex-discord-php)[rector/rector-src

Instant Upgrade and Automated Refactoring of any PHP code

136411.0k14](/packages/rector-rector-src)[lucianotonet/laravel-telescope-mcp

MCP Server extension for Laravel Telescope

2233.5k](/packages/lucianotonet-laravel-telescope-mcp)

PHPackages © 2026

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