Core watchers are enabled by default, including view (Edge), health_check, vine, and i18n,
which silently no-op when their host module is absent. The infrastructure integrations
job_schedule, redis, session, transmit, limiter, lock, drive, ally, notification,
and socket are off by default and subscribe to nothing until explicitly enabled.
| Watcher | Source | Recorded content |
|---|---|---|
request |
Request middleware and http:request_completed |
Method, URL, query, route, redacted headers and payload, status, duration, memory delta, client identity summary, optional response/session, Inertia component/prop keys, disconnect state; exact slow, status:<code>, and status:Nxx tags |
vine |
VineJS reporter patch | Validation error count, affected field names, and field/rule/message details; submitted values are never recorded |
limiter |
@adonisjs/limiter service methods |
Key, action, limit, remaining quota, retry delay, and store |
lock |
@adonisjs/lock service methods |
Lock key, acquired/denied/timeout outcome, wait duration, optional TTL, and contention signalling controlled by contentionMs |
query |
Lucid db:query |
SQL, serialized or hidden bindings, connection, model/method, duration, transaction/DDL flags, compact error |
exception |
Exception handler mixin and process observers | Name, message, code/status, stack, parsed frames, application code frame, request summary, serialized context |
log |
AdonisJS/Pino destination | Level, message, context, and source timestamp; self-generated Periscope logs are excluded |
event |
AdonisJS emitter | Event name, serialized payload, class-event identity, and listener count |
command |
Ace lifecycle | Command, arguments, flags, main-command state, exit code, duration, bounded redacted terminal output (captureOutput), error |
mail |
AdonisJS Mail lifecycle | Lifecycle event, mailer, envelope, subject, optional rendered bodies/raw MIME, message ID, metadata, response/error |
cache |
Bentocache events | Hit, miss, set, delete, or clear; store, key, cache layer/grace state, optional value |
model |
Lucid model lifecycle | Create, update, or delete; model, primary key, optional attributes and dirty diff |
gate |
Bouncer authorization events | Ability, decision, user ID, arguments, optional user/status/message |
dump |
dump() helper |
Safely serialized values and the application call site |
drive |
@adonisjs/drive service methods |
Operation, key, disk, duration, destination/size when available, and compact errors |
ally |
@adonisjs/ally service methods |
Provider, OAuth operation, duration, compact error, and safe user summary |
i18n |
@adonisjs/i18n translation methods |
Locale, translation identifier, and fallback state; interpolation parameters are never recorded |
http_client |
Node diagnostics channel for Undici | Method, URL, status, duration, redacted request/response headers, completion/error; exact slow (>= slowMs) and failed tags |
view |
Edge onRender hook |
Template name, render duration, and top-level data key names only—values are never read |
health_check |
AdonisJS core HealthChecks.run() |
Overall status plus per-check name, status, duration, and bounded message; failed tag on unhealthy reports |
job_schedule |
Pluggable queue adapters (BullMQ and @adonisjs/queue adapters included) |
Scheduled job metadata plus started/completed/failed status, job name, attempts, duration, and opt-in payload/result |
redis |
@adonisjs/redis diagnostics channel |
Command, argument count, duration, error, and opt-in arguments; AUTH arguments are always replaced |
session |
@adonisjs/session lifecycle events |
Initiated, committed, or migrated state with hashed session IDs and opt-in redacted values |
transmit |
@adonisjs/transmit broadcast hook |
Channel, event metadata, and opt-in bounded payload summary |
notification |
Pluggable notification adapters | Adapter, channel, notification, scalar recipient descriptor, sent/failed outcome, duration, and opt-in payload |
socket |
Pluggable socket adapters | Connection lifecycle and messages, transport/channel, scalar user identity, direction, size/duration, reason, and opt-in payload |
Watcher-specific options in the generated config control sensitive or expensive captures. All application-owned values pass through bounded serialization and recursive redaction before storage.
Request recording excludes static-asset traffic by default. Set watchers.request.captureStatic
to true only when asset requests are relevant to an investigation; ignorePaths still takes
precedence.
Queue and scheduled-task integrations use the exported QueueWatcherAdapter and
SchedulerWatcherAdapter contracts. BullMQ and experimental @adonisjs/queue adapters ship with
the package; third-party scheduler adapters register separately under
watchers.job_schedule.schedulers.
Notification and socket integrations use NotificationWatcherAdapter and SocketWatcherAdapter.
All adapter-backed watchers are opt-in, default to excluding application payloads, and must remain
best effort. Consumption examples and the complete authoring contracts are in
Authoring adapters.
Hooks and extensibility
Filter hooks can drop an entry before buffering, and tag hooks can add exact-match tags. Custom
watcher factories receive the application, recorder, and resolved config; custom stores implement
the portable PeriscopeStore boundary; dashboard.fanout accepts a factory for cross-process SSE
pub/sub. All extension points are safeguarded so diagnostics cannot break host code.
See Authoring adapters for hook examples, complete adapter interfaces, registration points, lifecycle requirements, custom watcher and store skeletons, and a pub/sub fanout implementation.
Testing your app with Periscope
The @rikology/adonisjs-periscope/testing subpath provides flush-and-poll assertions, entry
matching, scoped cleanup, and a Japa plugin backed by the configured recorder. Use it to assert
late-settling request batches without arbitrary sleeps. See
Testing for setup, signatures, and examples.
Operational commands
Periscope ships Ace commands for installation diagnosis, scoped clearing and pruning, shared pause/resume state, and portable batch import/export. See the CLI command reference for every flag, failure mode, and storage requirement.
FAQ
Why is the dashboard empty?
Check enabledIn and PERISCOPE_ENABLED, confirm the request middleware is first, enable Lucid
debug for query events, confirm the selected storage path/connection is writable, and generate
fresh traffic after Periscope has booted.
Why are database queries missing?
The query watcher consumes Lucid’s db:query event, which is emitted only when the connection has
debug: true. Also confirm watchers.query.enabled is not false.
Why are entries missing under sampling?
Sampling keeps or drops the whole batch. Raise recording.sampleRate, add a monitored tag, or use
recording.keepAlways for important exceptions, slow requests, or error responses.
Why can asynchronously emitted work appear after the request entry?
AdonisJS emitters and diagnostics sources may complete listener work after the host callback returns. Periscope assigns sequence numbers when signals are captured, tracks in-flight request completion work, and accepts late fragments into the same batch. The timeline orders by sequence; it does not block the host response to manufacture synchronous listener ordering.
Why did an entry contain [Truncated], [Circular], or [Unserializable]?
Those are deliberate safety markers from bounded serialization. Periscope limits depth, entry size, and hostile object traversal so diagnostics cannot hang or exhaust the application.
Can Periscope call an external service?
The shipped package code has no outbound telemetry path and CI forbids network APIs in package source. The HTTP client watcher observes diagnostics events; it does not issue requests.
Is it safe to expose /periscope publicly?
No. Keep it disabled in production by default. If exposure is required, use a real authorization policy, TLS, restrictive retention/capture settings, and a short explicit enablement window.