Skip to main content
The NightOwl agent receives whatever Nightwatch sends. That means all of Nightwatch’s filtering and redaction primitives work out of the box — and the agent itself buffers the payload as-received.

Sampling

Sampling lives in laravel/nightwatch and runs inside the customer’s PHP process. The trace decision is set at the start of the request and applied at the end — sensors record into the trace either way, but at flush time only sampled-in traces are shipped to the agent. That means the agent only sees and stores what Nightwatch already decided to keep, with no second-pass drop on the agent side. Configure it in .env:
When an entry point is sampled in, the entire trace — queries, cache events, logs, outgoing requests — is captured. Sampling happens at the trace boundary, not per-record, so you never end up with half a request. Set NIGHTWATCH_EXCEPTION_SAMPLE_RATE=1.0 to keep every exception regardless of the parent request’s sample decision. See the throughput guide for how to pick a rate.

In-code filtering

Use Nightwatch’s filtering API to exclude specific events inline:
For finer control, pause and resume around a block:
Useful for health-check endpoints, internal admin batch operations, or hot paths you don’t want to sample but also don’t want to pay for.

Context metadata

Attach custom key-value data to traces using Laravel’s Context facade (Laravel 11+):
Context data is captured by Nightwatch, stored by the agent alongside the request row, and shown in the request detail page as a collapsible JSON tree. The agent’s per-connection payload ceiling is 10 MB (MAX_PAYLOAD_BYTES) — oversized payloads are rejected with 5:ERROR, not silently truncated — so keep context entries small and structured rather than pushing large blobs through the tracer. Good things to stash in context:
  • Tenant / workspace / organization ID.
  • Feature flag decisions that affected this request.
  • User role or permission set.
  • Deploy-specific debugging flags you set temporarily during an incident.
Don’t stash secrets in Context — those entries are passed through verbatim.

Searching log context

The context you attach to a log — the array in Log::error('Payment failed', ['order_id' => 8412]) — is shown on the log’s detail page, but the Logs page search box does not match inside it by default. Log context is stored compressed, and PostgreSQL cannot decompress it while running a query, so the search falls back to the message and the page shows a “Narrowed search” note explaining that. Set NIGHTOWL_LOG_CONTEXT_SEARCHABLE=true to store it uncompressed and make it searchable. It trades storage for that, and existing logs need converting — see Searchable log context for the sizing check and the conversion command.

Redaction

PII redaction lives in laravel/nightwatch and runs inside the customer’s PHP process before the payload is shipped to the agent. Configure it in .env:
NIGHTWATCH_REDACT_HEADERS strips named headers from every request record. NIGHTWATCH_REDACT_PAYLOAD_FIELDS recursively replaces matching keys in the request payload with a [N bytes redacted] marker. Both are applied at record-assembly time, so neither the agent’s TCP buffer, SQLite WAL, nor PostgreSQL drain ever see the un-redacted values. Note: Nightwatch only writes the request payload for HTTP 500 responses, and only for application/json and form-encoded bodies. Response bodies are never written.

Combining the layers

A common production config looks like:
Combined with Nightwatch::ignore() around health-check endpoints and Context::add() for tenant IDs, you get a dataset that’s lean, safe to store, and actually queryable.