Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Request inspector

The inspector records recent requests so you can see what actually reached the upstream after the gateway rewrote, enriched or stripped it. It captures every request except the control plane (/_rustybin/*), the web console (/ui/*), the landing page (/) and /favicon.ico.

Each entry has: an inspector id, the request_id (X-Request-Id), timestamp, method, URI, path, query, HTTP version, every header, client IP, the X-Rustybin-Session value, the body (up to 64 KiB; UTF-8 as body, anything else as body_base64, with body_size and body_truncated), the response status and the time to response headers in latency_ms.

Entries live in a ring buffer of RUSTYBIN_INSPECTOR_CAPACITY entries (default 500, at most 10000); the oldest entry is evicted first.

Tag, list, fetch

Tag your traffic with X-Rustybin-Session (1 to 128 characters of A-Z a-z 0-9 . _ : -) to find it again among everyone else's:

POST {{base_url}}/anything/checkout?step=1
X-Rustybin-Session: docs-inspector
X-Request-Id: docs-inspector-0001
Content-Type: application/json
{"cart": 42}
HTTP 200

GET /_rustybin/requests lists entries newest first. Filters: ?session=, ?path_prefix=, ?limit= (default 100, capped at the capacity).

GET {{base_url}}/_rustybin/requests?session=docs-inspector&limit=10
HTTP 200
[Captures]
entry_id: jsonpath "$.requests[0].id"
[Asserts]
jsonpath "$.public_mode" == false
jsonpath "$.requests[0].method" == "POST"
jsonpath "$.requests[0].path" == "/anything/checkout"
jsonpath "$.requests[0].query" == "step=1"
jsonpath "$.requests[0].request_id" == "docs-inspector-0001"
jsonpath "$.requests[0].session" == "docs-inspector"
jsonpath "$.requests[0].body" == "{\"cart\": 42}"
jsonpath "$.requests[0].status" == 200
jsonpath "$.requests[0].latency_ms" exists
GET {{base_url}}/_rustybin/requests/{{entry_id}}
HTTP 200
[Asserts]
jsonpath "$.id" == "{{entry_id}}"
jsonpath "$.headers[?(@.name == 'x-rustybin-session')].value" nth 0 == "docs-inspector"
GET {{base_url}}/_rustybin/requests?path_prefix=/anything/checkout&limit=1
HTTP 200
[Asserts]
jsonpath "$.count" == 1

Live feed

GET /_rustybin/requests/stream is a Server-Sent Events feed with one request event per captured request (the event id is the inspector id, the data the full entry as JSON). It accepts the same filters as the list and sends keep-alive comments while idle:

curl -sN --max-time 2 "$BASE/_rustybin/requests/stream?session=docs-feed"

The feed never ends on its own (the example stops reading after two seconds); the web console uses it for its live traffic view.

Clearing

DELETE /_rustybin/requests?session=<id> removes one session's entries and needs no credentials. Without ?session= it clears everything, which is an instance-global mutation guarded by the admin token:

DELETE {{base_url}}/_rustybin/requests?session=docs-inspector
HTTP 200
[Asserts]
jsonpath "$.session" == "docs-inspector"
jsonpath "$.cleared" >= 1
# Clearing everything is a global mutation: it needs the admin token when one is configured.
DELETE {{base_url}}/_rustybin/requests
HTTP 401

DELETE {{base_url}}/_rustybin/requests
X-Rustybin-Admin-Token: {{admin_token}}
HTTP 200
[Asserts]
jsonpath "$.cleared" exists

Public mode

With RUSTYBIN_PUBLIC_MODE=true only requests carrying X-Rustybin-Session are captured, the list and the live feed require ?session= (400 otherwise) and only return that session's entries, and GET /_rustybin/requests/{id} only answers when ?session= names the session the entry belongs to.

  • The AI request inspector (/ai/requests/{id}) shows what the mock LLM made of a request (normalised prompt, token counts, redacted credentials) and links to the inspector entry.
  • A request bin gives a webhook sender or a logging plugin its own URL and history.