Skip to content

Add verbose output with tiered logging levels (-v and -vv)#3

Open
jundai-godaddy wants to merge 2 commits intomainfrom
jundai/add-verbose-flag-alias
Open

Add verbose output with tiered logging levels (-v and -vv)#3
jundai-godaddy wants to merge 2 commits intomainfrom
jundai/add-verbose-flag-alias

Conversation

@jundai-godaddy
Copy link
Collaborator

Summary

This PR adds comprehensive verbose output support with two levels of verbosity, along with fixes for ES module compatibility issues that were preventing verbose mode from working.

Features Added

Tiered Verbosity Levels

  • Level 1 (-v, --info): Basic output showing HTTP method, URL, status code, and duration
    → POST https://api.godaddy.com/v2/oauth2/token
    ← 200 POST https://api.godaddy.com/v2/oauth2/token (234ms)
  • Level 2 (-vv, --debug): Full output including headers, request/response bodies with automatic sensitive field redaction
    [Full JSON output with headers, request body, response body]

Automatic HTTP Logging

  • Introduced loggedFetch() wrapper that automatically logs HTTP requests
  • Extracts logging details from actual requests/responses, eliminating hardcoded duplication
  • Automatic timing and status code capture
  • Smart JSON response parsing for level 2 verbosity
  • No need to manually specify method/status in logging calls - prevents drift between code and logs

Security Enhancements

  • Automatic redaction of access_token and accessToken fields in response logs
  • Recursive redaction for nested objects
  • Follows existing redaction patterns for Authorization headers
  • Keeps logs clean and secure while still being useful for debugging

Bug Fixes

ES Module Compatibility Issues

  • Fixed __dirname is not defined error: Added __dirname and __filename shims in require-shim.js for dependencies expecting CommonJS globals
  • Fixed worker thread error: Marked pino-pretty as external dependency to avoid bundling worker thread code that breaks at runtime
  • Fixed pino transport issue: Changed from pino transport API to direct stream usage to eliminate worker thread dependency

These fixes ensure that verbose mode actually works when the CLI is installed globally.

CLI Options

  • -v, --verbose: Incrementing flag (can be used multiple times: -vv)
  • --info: Alias for level 1 verbosity (-v)
  • --debug: Alias for level 2 verbosity (-vv)

Examples

# Basic logging - just URL, status, and time
godaddy -v auth login
godaddy --info auth login

# Full logging - headers, bodies, everything
godaddy -vv auth login
godaddy --debug auth login

# Multiple v flags also work
godaddy -vv auth login

Implementation Highlights

  • DRY principle: Single loggedFetch() wrapper handles all HTTP logging
  • No hardcoded values: Method/status extracted from actual requests/responses
  • Level-aware: Only parses JSON bodies when verbosity level requires it
  • Visual feedback: Shows (verbose output enabled) or (verbose output enabled: full details) when enabled

Testing

Tested with:

  • godaddy -v auth login - Basic logging works
  • godaddy -vv auth login - Full logging works with redacted tokens
  • godaddy --info env get - Alias works
  • godaddy --debug env get - Alias works
  • No worker thread errors when installed globally

🤖 Generated with Claude Code

jundai-godaddy and others added 2 commits February 12, 2026 13:53
Added standard -v and --verbose flags for enabling verbose output, while
keeping --debug as an alias. This follows common CLI conventions where -v
is the standard flag for verbose logging.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit adds comprehensive verbose output support with two levels of
verbosity, along with fixes for ES module compatibility issues.

## New Features

### Tiered Verbosity Levels
- **Level 1 (-v, --info)**: Basic output showing HTTP method, URL, status,
  and duration
- **Level 2 (-vv, --debug)**: Full output including headers, request/response
  bodies with sensitive field redaction

### Automatic HTTP Logging
- Introduced `loggedFetch()` wrapper that automatically logs HTTP requests
- Extracts logging details from actual requests/responses, eliminating
  hardcoded duplication
- Automatic timing and status code capture
- Smart JSON response parsing for level 2 verbosity

### Security
- Automatic redaction of `access_token` and `accessToken` fields in logs
- Recursive redaction for nested objects
- Follows existing redaction patterns for Authorization headers

## Bug Fixes

### ES Module Compatibility
- Added `__dirname` and `__filename` shims in require-shim.js for
  dependencies expecting CommonJS globals
- Marked pino-pretty as external dependency to avoid bundling worker thread
  code that breaks at runtime
- Changed from pino transport API to direct stream usage to eliminate worker
  thread dependency

### User Experience
- Added visual indicator when verbose output is enabled
- Clear messaging distinguishing between basic and full verbosity levels

## Implementation Details

### CLI Options
- `-v, --verbose`: Incrementing flag (use multiple times for higher levels)
- `--info`: Alias for level 1 verbosity
- `--debug`: Alias for level 2 verbosity

### Code Quality
- DRY principle: Single `loggedFetch()` wrapper handles all HTTP logging
- No hardcoded method/status values in logging calls
- Automatic body parsing based on content-type
- Level-aware logging prevents unnecessary work at lower verbosity

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
logger.debug(`→ ${options.method} ${options.url}`);
}
};

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This logs sensitive data returned by
an access to oauthTokenUrl
as clear text.

Copilot Autofix

AI 3 days ago

In general: avoid logging full URLs that may contain sensitive information (query strings, path segments) and avoid logging any token/credential endpoints at low verbosity. Instead, log only high‑level, non‑sensitive details (HTTP method, status code, maybe a truncated or sanitized URL) and reserve detailed information for higher verbosity with explicit redaction.

Best targeted fix here without changing existing behavior more than necessary:

  • For verbosityLevel === 1, stop including the full options.url in the log messages in logHttpRequest and logHttpResponse. We can still log the method and, for responses, the status and duration, which preserves the intent of “basic” verbosity while eliminating the sensitive URL from that path.
  • For verbosityLevel >= 2, we already log a structured object including url, and that is where advanced debugging is expected; we leave that as‑is since the reported sink is the string interpolation at line 71, not the structured object.

Concretely:

  • In src/services/logger.ts:
    • Change logHttpRequest so that the branch verbosityLevel === 1 logs only the HTTP method (or a generic message) instead of → ${options.method} ${options.url}.
    • Change logHttpResponse so that the branch verbosityLevel === 1 logs only the status, method, and optional duration, but not options.url.

No new imports or helpers are required; we only adjust the log message strings.

Suggested changeset 1
src/services/logger.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/services/logger.ts b/src/services/logger.ts
--- a/src/services/logger.ts
+++ b/src/services/logger.ts
@@ -68,7 +68,8 @@
 			`→ ${options.method} ${options.url}`,
 		);
 	} else if (verbosityLevel === 1) {
-		logger.debug(`→ ${options.method} ${options.url}`);
+		// Avoid logging full URL at basic verbosity to prevent leaking sensitive data
+		logger.debug(`→ ${options.method}`);
 	}
 };
 
@@ -98,8 +99,9 @@
 			}`,
 		);
 	} else if (verbosityLevel === 1) {
+		// Avoid logging full URL at basic verbosity to prevent leaking sensitive data
 		logger.debug(
-			`← ${options.status} ${options.method} ${options.url} ${
+			`← ${options.status} ${options.method} ${
 				options.duration ? `(${options.duration}ms)` : ""
 			}`,
 		);
EOF
@@ -68,7 +68,8 @@
`→ ${options.method} ${options.url}`,
);
} else if (verbosityLevel === 1) {
logger.debug(`→ ${options.method} ${options.url}`);
// Avoid logging full URL at basic verbosity to prevent leaking sensitive data
logger.debug(`→ ${options.method}`);
}
};

@@ -98,8 +99,9 @@
}`,
);
} else if (verbosityLevel === 1) {
// Avoid logging full URL at basic verbosity to prevent leaking sensitive data
logger.debug(
`← ${options.status} ${options.method} ${options.url} ${
`← ${options.status} ${options.method} ${
options.duration ? `(${options.duration}ms)` : ""
}`,
);
Copilot is powered by AI and may make mistakes. Always verify output.
Comment on lines +102 to +104

if (Array.isArray(obj)) {
return obj.map(redactSensitiveFields);

Check failure

Code scanning / CodeQL

Clear-text logging of sensitive information High

This logs sensitive data returned by
an access to oauthTokenUrl
as clear text.

Copilot Autofix

AI 3 days ago

In general, to fix clear-text logging of sensitive information you must either (1) avoid logging sensitive values at all, or (2) ensure they are consistently redacted before being written to logs. In this code, the problem arises because logHttpResponse always includes the full options.url in the log message string; for calls like the OAuth token exchange, that URL is considered sensitive by the analysis and should not be logged verbatim.

The minimal, behavior-preserving fix is to treat URLs as potentially sensitive and avoid logging them in the human-readable message string for responses (and, ideally, for requests as well), while still keeping them in the structured log object for high-verbosity, where operators can decide whether such logs are acceptable. Specifically:

  • Leave the structured object fields (url, headers, body, etc.) as-is for verbosity level ≥ 2, since that’s already subject to redaction logic and is clearly marked as debug-level logging.
  • Change the string passed as the second argument to logger.debug in logHttpResponse (both branches: verbosityLevel >= 2 and verbosityLevel === 1) so that it no longer includes ${options.url}.
  • Optionally, for symmetry and defense in depth, also remove the URL from the logHttpRequest message string, although CodeQL only flagged the response path.

Concretely, in src/services/logger.ts:

  • In logHttpResponse, replace:
    • The debug message template at lines 96–98 with one that omits ${options.url} but keeps status, method, and duration.
    • The debug message template at lines 101–104 similarly.
      No new methods or imports are required; we only adjust the formatting strings.

Suggested changeset 1
src/services/logger.ts

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/src/services/logger.ts b/src/services/logger.ts
--- a/src/services/logger.ts
+++ b/src/services/logger.ts
@@ -93,13 +93,13 @@
 				body: options.body,
 				duration: options.duration,
 			},
-			`← ${options.status} ${options.method} ${options.url} ${
+			`← ${options.status} ${options.method} ${
 				options.duration ? `(${options.duration}ms)` : ""
 			}`,
 		);
 	} else if (verbosityLevel === 1) {
 		logger.debug(
-			`← ${options.status} ${options.method} ${options.url} ${
+			`← ${options.status} ${options.method} ${
 				options.duration ? `(${options.duration}ms)` : ""
 			}`,
 		);
EOF
@@ -93,13 +93,13 @@
body: options.body,
duration: options.duration,
},
`← ${options.status} ${options.method} ${options.url} ${
`← ${options.status} ${options.method} ${
options.duration ? `(${options.duration}ms)` : ""
}`,
);
} else if (verbosityLevel === 1) {
logger.debug(
`← ${options.status} ${options.method} ${options.url} ${
`← ${options.status} ${options.method} ${
options.duration ? `(${options.duration}ms)` : ""
}`,
);
Copilot is powered by AI and may make mistakes. Always verify output.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant