Requizon

Configuration reference

Every key in config/requizon.php, its environment variable and its default.

Requizon works with no configuration file at all. When you want to change something, publish it:

php artisan vendor:publish --tag=requizon-config

The published config/requizon.php explains every key in its comments. This page is the same information as a table, with a link to the page that covers each group in depth.

Nested arrays replace, they do not merge

Laravel merges the package defaults into your file one top-level key at a time. If your file has a recording array, it replaces the whole default recording array, so a key you leave out of it is missing rather than defaulted. Keep each nested array complete, and re-check it after upgrading Requizon.

Switches#

KeyEnvDefaultPurpose
enabled REQUIZON_ENABLED true The master switch. false registers no recording middleware, no dashboard routes and no scheduled commands. Migrations still load.
instrument.laravel_client REQUIZON_INSTRUMENT_LARAVEL true Installs the recording middleware on Laravel's HTTP client. false leaves the client alone and records only the Guzzle stacks you instrument.
instrument.promise_fallback REQUIZON_PROMISE_FALLBACK true Records a transfer whose handler never reported transfer stats, timing it by wall clock. See the promise fallback.
instrument.discovery REQUIZON_DISCOVERY false Hands a recording client to SDKs that resolve a PSR-18 client through php-http/discovery. Does nothing unless that package is installed. See client discovery.

What is recorded, and under which name#

KeyDefaultPurpose
ignore_hosts [] Str::is() host patterns that are never recorded. Ignoring hosts
apis [] API name to Str::is() host patterns, and the redaction keys that API alone gets. A host no pattern matches is named after itself. Naming APIs
paths.max_segments 4 Path segments kept before the rest is replaced with /*.
paths.max_segment_length 40 A longer segment is treated as an identifier and stored as :id.
paths.max_length 255 The stored path is cut to this many bytes. It must fit the VARCHAR(255) column.
paths.rewrite [] Str::is() patterns matched against the raw path, each mapped to the path to record instead, for identifiers the normaliser cannot recognise. First match wins. Rewriting paths
paths.patterns [] An allow-list of normalised paths. When set, anything unmatched is stored under other_label. Paths and table size
paths.other_label 'other' The path recorded for calls that match none of paths.patterns.
paths.store_raw true Keep the path each call was made to beside the normalised one. REQUIZON_STORE_RAW_PATHS sets it from the environment. The path as it was called
paths.raw_long_segments false Keep segments longer than max_segment_length in the raw path instead of storing them as ***.
paths.raw_unmasked [] Str::is() patterns for raw paths stored as called, unmasked by rewrites or the length rule. The redaction rules still apply.

An apis entry is either its host patterns, or an array that names them under hosts alongside the redaction keys that apply to that API alone. Both shapes can sit in the same list, and an entry that leaves its patterns bare can still carry the keys:

'apis' => [
    'nausys' => ['ws.nausys.com', '*.nausys.com', 'redact' => ['l']],
    'stripe' => [
        'hosts' => ['api.stripe.com', 'files.stripe.com'],
        'redact' => ['card_number', 'cvc'],
    ],
    'sedna' => [
        'hosts' => ['sedna.example.com'],
        'redact_exact' => ['l', 'p'],
    ],
],

redact matches a parameter name by substring and redact_exact by the whole name, the same split as the two global lists below, and both are added to them for that API rather than replacing them. Rules are keyed by the resolved API name, so an entry with keys and no hosts carries them for a name that resolveApiUsing() mints. What they cover is on Redaction and stored data.

Recording and redaction#

KeyDefaultPurpose
recording.response_body_max_bytes 65536 How much of a stored response body is kept, cut after redaction.
recording.response_body_read_bytes 262144 How far a response body is read for the failure detector and for redaction, separately from how much is stored. A JSON response past it is cut before its end and reaches the detector as a raw string. When response_body_max_bytes is larger, that is the limit instead.
recording.request_body_max_bytes 4096 How much of an unparsed request body is stored when store_unparsed_bodies is on.
recording.query_max_bytes 4096 The cap on a stored query string's JSON. Parameters that do not fit are dropped whole and counted under _truncated, so a thousand ids[] cost one row and not the table.
recording.max_body_read_bytes 262144 A request body larger than this is never read, only measured. Keeps file uploads out of memory.
recording.store_unparsed_bodies false Store XML, SOAP and other bodies that cannot be parsed into named parameters verbatim, instead of by shape.
recording.success_bodies false Keep the response bodies of successful calls too: true for every API, or a list of API names and host patterns. REQUIZON_SUCCESS_BODIES takes true or a comma separated list. Successful response bodies
recording.success_body_sample_rate 1.0 The share of covered successes whose body is kept, from 0.0 to 1.0. REQUIZON_SUCCESS_BODY_SAMPLE_RATE sets it from the environment.
recording.redact_patterns pass, secret, token, apikey, api_key, auth A parameter whose lowercased name contains one of these is stored as ***. It covers the query, the request body, the parsed body of a failed response and header names, on every API.
recording.redact_exact p, l, pwd A parameter with exactly this name is stored as ***. One API's own keys go on its apis entry instead. Redaction and stored data

Header capture#

recording.headers decides which headers are stored, with a mode per direction. Requests and responses each take none, failures (calls recorded as a failure, and successes whose body is kept) or all.

KeyEnvDefaultPurpose
recording.headers.request REQUIZON_REQUEST_HEADERS 'none' Request headers are not stored until you ask for them.
recording.headers.response REQUIZON_RESPONSE_HEADERS 'failures' Response headers are stored on the rows that keep a response body: failures, and the successes success_bodies keeps.
recording.headers.only — [] When set, only headers matching these Str::is() patterns are stored, such as x-ratelimit-* or retry-after.
recording.headers.except — [] Patterns removed from whatever only left.
recording.headers.redact — authorization, proxy-authorization, cookie, set-cookie, *api-key*, *subscription-key*, x-functions-key Header names kept with every value replaced by ***, matched case-insensitively as Str::is() patterns. Your list replaces this one, though a published config with no headers.redact key at all still gets it. Headers
recording.headers.max_bytes — 16384 The cap on each message's stored header JSON. A header that does not fit is dropped whole and counted under _truncated.

The names in redact_patterns and redact_exact, and the ones an API's apis entry adds, mask a header as well as a parameter, so a provider's X-Partner-Key named there is masked without being named twice.

Dashboard#

KeyEnvDefaultPurpose
path REQUIZON_PATH 'requizon' The URI the dashboard is served from.
domain REQUIZON_DOMAIN null Serve the dashboard from a dedicated host. null serves it on every host the application answers.
middleware — ['web'] Applied to every dashboard route, before Requizon's own check of the viewRequizon gate.
dashboard.windows — [24, 72, 168, 336] The time windows, in hours, offered by the window selector.
dashboard.default_window — 72 The window shown first. A value not in windows falls back to the first entry.
dashboard.per_page — 50 Rows per page on the requests list. The dashboard
dashboard.recent_minutes REQUIZON_RECENT_MINUTES 15 What every page counts as "right now": failures in this stretch are called out above the charts and sort their rows to the top. Failures right now
dashboard.max_paths — 500 The most rows on an API's paths page: those with the most failures, then the most requests. A guard for APIs whose paths are not bounded yet.

Calls that fail every time#

KeyDefaultPurpose
fingerprint.ignore [] Parameter names, as Str::is() patterns in any case and at any depth, left out of the fingerprint because they change on every call: timestamps, nonces, request ids.
fingerprint.min_attempts 3 Failures a call needs before it is listed.
fingerprint.min_span_minutes 10 The least time between its first and last failure, so one call retried in a burst is not listed.
fingerprint.max_results 100 The most calls listed on a paths page. Calls that fail every time

Storage, retention and scheduling#

KeyEnvDefaultPurpose
connection REQUIZON_DB_CONNECTION null The database connection Requizon's tables live on. null is the default connection. MySQL 8.0.19+, MariaDB 10.5+, PostgreSQL 9.5+ and SQLite 3.24+ are supported.
retention.detail_days — 14 Days requizon_http_requests rows are kept.
retention.aggregate_days — 365 Days hourly rollup rows are kept.
schedule.enabled REQUIZON_SCHEDULE true Register Requizon's commands on Laravel's scheduler: aggregate, prune, detect and the daily digest. false leaves scheduling to you.
schedule.aggregate_hours — 2 How many closed hours before the one under way each scheduled aggregate run rebuilds. Hours missed while the scheduler was down are caught up whatever this is.
schedule.prune_at — '03:00' The daily time requizon:prune runs, in the scheduler's timezone. Retention and scheduling
schedule.daily_digest_at REQUIZON_DAILY_DIGEST_AT '09:00' The daily time requizon:daily-digest sends the alerts set to go out in the digest.

Alerts and notifications#

alerts.detectors holds one entry per alert, each with enabled and its thresholds. They are listed with their defaults on Alerts, and the one that does nothing until configured is alerts.detectors.latency_high.targets.

KeyEnvDefaultPurpose
alerts.notifications.channels REQUIZON_NOTIFY_CHANNELS [] Any of mail, slack and webhook, comma separated in the environment. Empty sends nothing, and the alerts page is the only record.
alerts.notifications.mail.to REQUIZON_NOTIFY_MAIL [] The addresses alerts are mailed to, comma separated in the environment.
alerts.notifications.slack.webhook_url REQUIZON_SLACK_WEBHOOK_URL null An incoming webhook URL, or a channel to post to through the bot token in services.slack.notifications. Needs laravel/slack-notification-channel.
alerts.notifications.webhook.url REQUIZON_WEBHOOK_URL null Where the webhook channel POSTs its JSON. webhook.headers adds headers to it, and webhook.timeout (5 seconds) bounds it.
alerts.notifications.routes — [] Channels per severity (critical, warning, info) and for the digest. A severity not listed goes to every channel.
alerts.notifications.repeat_minutes REQUIZON_NOTIFY_REPEAT_MINUTES 360 How often an open alert is sent again until someone acknowledges it. 0 sends no reminders.
alerts.notifications.resolved — true Send a recovery once an alert clears.
alerts.notifications.cooldown_minutes — 60 An alert that clears and comes back within this long of its latest notification stays quiet.
alerts.notifications.types — every type, immediate Each alert's severity, and whether it is sent immediately, in the digest or not at all (none), with its own repeat_minutes and resolved if you like. Severities, routes and types

Callbacks#

Some behaviours need code rather than a value, and are registered on BoringO11y\Requizon\Requizon, usually in the boot() method of your published RequizonServiceProvider:

MethodReplacesCovered in
resolveApiUsing() The apis host map. Returning null falls back to it. Naming APIs
resolvePathUsing() The built-in path normaliser. Returning null falls back to it. Paths and table size
redactUsing() Nothing. It receives what the name rules already redacted, for request parameters and for the parsed body of a failed response. Redaction and stored data
redactPathUsing() Nothing. It receives the raw path's segments after the built-in masking and returns the ones to store. Paths and table size
detectFailuresUsing() Nothing. Without it no successful response body is read. Failure detection
fingerprintUsing() The built-in fingerprint of method, host, raw path and parameters. Returning null falls back to it. Failure detection
discoverUsing() The plain Guzzle client handed to SDKs through client discovery. What gets recorded
routeMailNotificationsTo(), routeSlackNotificationsTo(), routeWebhookNotificationsTo() Nothing. They set where alerts go, and a destination in the config wins over them. Alerts
auth() The viewRequizon gate check. The base provider registers one for you. The dashboard

After changing configuration#

If you cache configuration in production, run php artisan config:cache again after editing the file, and restart long-running processes (queue workers, Octane) so they pick up the new values. php artisan about shows whether the HTTP client is instrumented and the path the dashboard is served from, which is a quick way to confirm what the running configuration actually is.

A change to paths applies to calls recorded from then on. To fold the rows already stored into the new paths, run requizon:merge-paths once the new configuration is live everywhere.

Common questions

How do I turn Requizon off in my test suite?

Set REQUIZON_ENABLED=false in phpunit.xml. With the master switch off Requizon registers no recording middleware, no dashboard routes and no scheduled commands. Left on, every Http::fake() response your tests produce is written to requizon_http_requests.

Install Requizon today.

Checkout ends with your license key, and the installation guide takes it from there.