The debug mode feature allows you to log detailed request/response information for troubleshooting. Three levels are available:
disabled— No additional debug logging (default behavior).no_content— Log all request/response metadata and parameters, but redact content and thinking/reasoning fields per provider.full_body— Log full request and response including all bodies, with sensitive fields (api_key,token) redacted.
Debug mode is configured per provider in its gateway_policy section:
providers:
my_provider:
gateway_policy:
streaming_mode: "auto"
debug_mode: "no_content" # Provider-specific debug modeValid values: "disabled", "no_content", "full_body".
The obsolete value "headers_only" is no longer accepted — it will cause
a Pydantic validation error at startup with a clear message listing the valid
values.
| Mode | Headers | Params | Content | Thinking | Sensitive fields |
|---|---|---|---|---|---|
| disabled | ❌ | ❌ | ❌ | ❌ | — |
| no_content | ✅ | ✅ | ███ | ███ | ███ |
| full_body | ✅ | ✅ | ✅ | ✅ | ███ |
- Sensitive fields (
api_key,token,secret,password,Authorization) are always redacted in bothno_contentandfull_bodymodes.
When debug_mode: "no_content", the gateway redacts content and
thinking/reasoning fields. The redaction paths are provider-specific:
| Direction | Redacted paths |
|---|---|
| Request | messages.*.content, messages.*.content.*.text, messages.*.content.*.image_url |
| Response | choices.*.message.content, choices.*.delta.content, choices.*.delta.reasoning_content |
| Direction | Redacted paths |
|---|---|
| Request | contents.*.parts.*.text, systemInstruction.parts.*.text |
| Response | candidates.*.content.parts.*.text |
| Direction | Redacted paths |
|---|---|
| Request | messages.*.content, messages.*.content.*.text, system |
| Response | content.*.text, content.*.thinking, content.*.data |
| SSE | content_block.text, content_block.thinking, delta.text, delta.thinking |
All replaced values become the literal string "***".
When no_content or full_body is enabled, streaming is automatically
disabled for that provider. The entire response is buffered before logging
and returned to the client as a single Response (not StreamingResponse).
This is necessary because debug mode requires the complete request/response trace for logging. Streaming would bypass the buffering step.
When debug mode is enabled (no_content or full_body), retry policies
are automatically disabled. This is because debug mode requires a single,
deterministic request/response trace — retries would obscure which attempt
succeeded.
A WARNING is logged at startup if both debug mode and retry are configured for the same provider:
WARNING: [Gateway Startup] Instance 'my_provider': Retry policy is CONFIGURED but
WILL BE IGNORED because debug mode 'full_body' takes priority. Disable debug mode
to restore retry behavior.
If you need both debug logging and retry resilience, use debug mode only for troubleshooting and disable it for normal operation.
Debug logs are written to standard output using Python's logging module:
Request to provider_name: POST /v1/chat/completions
Request headers: {'content-type': 'application/json', 'authorization': 'Bearer ***'}
Request body: {"model": "gpt-4", "messages": [{"role": "user", "content": "***"}]}
Response from provider_name: 200
Response headers: {'content-type': 'application/json'}
Response body: {"choices": [{"message": {"content": "***"}}]}
When running in Docker (via docker-compose), the container runtime's log
driver (typically json-file) captures stdout line-by-line and prepends an
ISO 8601 timestamp. Each line has its own timestamp, even continuation
lines of multi-line log messages. This is normal container behavior and does
not indicate streaming.
Multiline bodies are collapsed — literal newlines are replaced with the
escape sequence \n before logging. This produces clean single-line output:
Response body: data: {"choices":[{"delta":{"content":"***"}}]}\ndata: [DONE]\n\n
The following fields are always redacted in both full_body and
no_content modes:
| Field | Logged as |
|---|---|
api_key |
"***" |
token |
"***" |
secret |
"***" |
password |
"***" |
Authorization header (Bearer token) |
Bearer *** |
Other auth headers (x-goog-api-key, x-api-key) |
*** |
providers:
gemini_production:
gateway_policy:
debug_mode: "no_content"
streaming_mode: "auto" # Will be disabled automaticallyproviders:
deepseek_main:
gateway_policy:
debug_mode: "full_body"providers:
openai_prod:
# Normal operation
gateway_policy:
debug_mode: "disabled"
gemini_debug:
# Debug without exposing content
gateway_policy:
debug_mode: "no_content"
anthropic_full:
# Show everything except sensitive fields
gateway_policy:
debug_mode: "full_body"- Debug mode automatically disables streaming for the affected providers
- Debug mode automatically disables retry policies — a WARNING is logged at startup
- Content fields are redacted per provider type in
no_contentmode - Sensitive fields (
api_key,token,secret,password) are always redacted - Debug logs are written to standard output, captured by systemd/journald or docker-compose
- Multiline SSE bodies are collapsed to single lines for clean log output
- The
"headers_only"value is no longer valid — use"no_content"instead - Debug mode does NOT affect adaptive batching: the background worker's adaptive batch controller operates independently of per-request debug logging. Retries disabled by debug mode apply to the gateway, not to the worker's probe verification loop.