Skip to content

Watchers and troubleshooting

Understand recorded signals, capture behavior, extension hooks, and common failures.

Updated View as Markdown

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.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close