-
Notifications
You must be signed in to change notification settings - Fork 16
feat(cli): add HTTP debug logging #485
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,80 @@ | ||
| /* | ||
| * Copyright Elasticsearch B.V. and contributors | ||
| * SPDX-License-Identifier: Apache-2.0 | ||
| */ | ||
|
|
||
| const REDACTED_HEADERS = new Set([ | ||
| 'authorization', | ||
| 'proxy-authorization', | ||
| 'x-api-key', | ||
| 'cookie', | ||
| 'set-cookie', | ||
| ]) | ||
|
Comment on lines
+6
to
+12
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We'll need to validate this list by scanning each API codebase to ensure these are the only values with the potential to leak secrets. |
||
|
|
||
| let cliDebugEnabled = false | ||
|
|
||
| /** | ||
| * Enables or disables HTTP debugging for the current CLI process. | ||
| */ | ||
| export function setHttpDebugEnabled (enabled: boolean): void { | ||
| cliDebugEnabled = enabled | ||
| } | ||
|
|
||
| /** | ||
| * Returns whether HTTP debug output is enabled by CLI flag or environment. | ||
| */ | ||
| export function isHttpDebugEnabled (): boolean { | ||
| return cliDebugEnabled || process.env['ELASTIC_DEBUG'] === '1' | ||
| } | ||
|
|
||
| function writeHeaders (prefix: string, headers: RequestInit['headers']): void { | ||
| for (const [name, value] of new Headers(headers)) { | ||
| const printableValue = REDACTED_HEADERS.has(name.toLowerCase()) ? '(redacted)' : value | ||
| process.stderr.write(`${prefix} ${name}: ${printableValue}\n`) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will violate the requirement that all stdout/stderr output be able to be parsed as valid JSON when |
||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Executes a fetch call and writes opt-in request and response diagnostics to stderr. | ||
| * | ||
| * Credential-bearing headers are redacted case-insensitively. The response is | ||
| * cloned before its body is inspected so callers can consume the original body. | ||
| */ | ||
| export async function fetchWithHttpDebug ( | ||
| fetchImplementation: typeof fetch, | ||
| url: string, | ||
| init: RequestInit | ||
| ): Promise<Response> { | ||
| if (!isHttpDebugEnabled()) { | ||
| return fetchImplementation(url, init) | ||
| } | ||
|
|
||
| process.stderr.write(`> ${init.method ?? 'GET'} ${url}\n`) | ||
| writeHeaders('>', init.headers) | ||
| if (typeof init.body === 'string') { | ||
| process.stderr.write(`\n${init.body}\n`) | ||
| } | ||
|
|
||
| let response: Response | ||
| try { | ||
| response = await fetchImplementation(url, init) | ||
| } catch (error) { | ||
| process.stderr.write(`< Request failed: ${String(error)}\n`) | ||
| throw error | ||
| } | ||
|
|
||
| const statusText = response.statusText.length > 0 ? ` ${response.statusText}` : '' | ||
| process.stderr.write(`< ${response.status}${statusText}\n`) | ||
| writeHeaders('<', response.headers) | ||
|
|
||
| try { | ||
| const body = await response.clone().text() | ||
| if (body.length > 0) { | ||
| process.stderr.write(`\n${body}\n`) | ||
| } | ||
| } catch (error) { | ||
| process.stderr.write(`< Response body unavailable: ${String(error)}\n`) | ||
| } | ||
|
|
||
| return response | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the whole, providing a single interface FetchOptions {
debug?: boolean
}This gives us a place to add new options as we need them. |
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be good to also add a
--verbose/-vflag so an env var isn't the only way to do this.