# Debugging gogcli API Requests with the Verbose Flag: A Complete Guide

> Debug gogcli API requests effectively using the verbose flag. Expose detailed request metadata retry attempts and authentication flow to stderr.

- Repository: [Peter Steinberger/gogcli](https://github.com/steipete/gogcli)
- Tags: how-to-guide
- Published: 2026-02-16

---

**Enable verbose logging in gogcli by passing the `-v` flag to set the internal logger to debug level, which exposes detailed API request metadata, retry attempts, and authentication flow information to stderr.**

The `steipete/gogcli` tool provides a streamlined interface for interacting with Google APIs from the command line. When troubleshooting failed requests, rate limiting, or authentication issues, understanding how to leverage the verbose logging system is essential for diagnosing the root cause quickly.

## How the Verbose Flag Configures gogcli Logging

The application uses Go's standard library **`log/slog`** package for structured diagnostics. The global logger initialization happens in [`internal/cmd/root.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/root.go) during the command execution lifecycle.

### Flag Declaration and Level Assignment

The `RootFlags` struct defines the verbose option using struct tags for the Kong CLI parser:

```go
type RootFlags struct {
    Verbose bool `help:"Enable verbose logging" short:"v"`
}

```

During the `Execute` function in [`internal/cmd/root.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/root.go), the code evaluates this flag to determine the appropriate log level:

```go
logLevel := slog.LevelWarn          // default
if cli.Verbose {                    // –v supplied
    logLevel = slog.LevelDebug
}
slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
    Level: logLevel,
})))

```

This configuration ensures that when you pass `-v`, the logger captures **Debug** level messages while writing all output to **stderr**, keeping stdout clean for command results.

## What Debug Output Reveals About API Requests

With debug logging enabled, gogcli exposes internal state from the `internal/googleapi` package, which handles all Google HTTP interactions. The most valuable diagnostic information appears in the transport layer and authentication modules.

### Transport Layer Debugging in transport.go

The [`internal/googleapi/transport.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/transport.go) file implements retry logic with exponential backoff. When the verbose flag is active, you will see detailed retry metadata:

- **`rate limited, retrying`**: Displays the calculated delay duration, current attempt number, and maximum retry limit
- **`server error, retrying`**: Shows the HTTP status code (e.g., 502, 503) and retry timing

Example debug output:

```

2026-02-16T10:23:12Z DEBUG rate limited, retrying delay=1.2s attempt=1 max_retries=5
2026-02-16T10:23:13Z DEBUG server error, retrying status=502 attempt=1

```

### Authentication Flow in client.go

The [`internal/googleapi/client.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/client.go) file logs credential creation and scope configuration. Debug messages reveal:
- Which service account file is being loaded
- Which OAuth scopes are being requested for the API client

This is critical when troubleshooting "permission denied" errors or scope-related failures.

### Circuit Breaker State Changes

In [`internal/googleapi/circuitbreaker.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/circuitbreaker.go), the verbose flag exposes:
- When the circuit breaker opens or closes
- Success/failure counts triggering state transitions
- Reset attempts after failure bursts

This helps diagnose intermittent 5xx errors that trigger the circuit breaker to open, temporarily halting requests.

## Practical Examples for Debugging gogcli API Requests

### Basic Verbose Usage

Run any command with the `-v` flag to enable debug output:

```bash

# List Google Drive files with debugging enabled

gogcli -v drive ls

```

### Troubleshooting Rate Limits

When sending emails through Gmail, watch for 429 responses and retry behavior:

```bash
gogcli -v gmail send \
    --to recipient@example.com \
    --subject "Test Message" \
    --body "Debugging API requests"

```

Expected debug output during rate limiting:

```

2026-02-16T12:05:04Z DEBUG rate limited, retrying delay=2s attempt=1 max_retries=5
2026-02-16T12:05:06Z DEBUG rate limited, retrying delay=4s attempt=2 max_retries=5

```

### Separating Debug Logs from Command Output

Since debug messages write to stderr and command results write to stdout, you can pipe clean JSON while preserving diagnostics:

```bash
gogcli -v --json gmail list 2>debug.log | jq '.messages[] | .id'

```

This captures verbose API debugging information in `debug.log` while `jq` processes only the JSON message IDs from stdout.

## Summary

- **Verbose logging** in gogcli is controlled by the `-v` flag, which switches the internal `slog` logger from `LevelWarn` to `LevelDebug` in [`internal/cmd/root.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/root.go).
- **Debug output** appears on **stderr**, keeping stdout clean for command results and enabling log separation via shell redirection.
- **Transport layer** messages in [`internal/googleapi/transport.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/transport.go) reveal retry attempts, rate-limit delays, and HTTP error codes.
- **Authentication debugging** in [`internal/googleapi/client.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/client.go) exposes credential files and OAuth scopes being used.
- **Circuit breaker state** changes are visible in [`internal/googleapi/circuitbreaker.go`](https://github.com/steipete/gogcli/blob/main/internal/googleapi/circuitbreaker.go), helping diagnose intermittent service failures.

## Frequently Asked Questions

### How do I enable verbose logging in gogcli?

Pass the `-v` or `--verbose` flag immediately after the `gogcli` command and before subcommands. For example: `gogcli -v drive ls`. This flag is defined in the `RootFlags` struct within [`internal/cmd/root.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/root.go) and configures the global `slog` logger to output debug-level messages to stderr.

### What information does the verbose flag reveal about API requests?

When enabled, the verbose flag exposes detailed metadata from the `internal/googleapi` package, including HTTP retry attempts with calculated backoff delays, rate-limit responses showing `Retry-After` headers, server error codes (502, 503), credential file paths, requested OAuth scopes, and circuit breaker state transitions between open and closed states.

### Why do debug messages appear on stderr instead of stdout?

The logger initialization in [`internal/cmd/root.go`](https://github.com/steipete/gogcli/blob/main/internal/cmd/root.go) explicitly configures `slog.NewTextHandler` to write to `os.Stderr`. This design separates diagnostic information from command output, allowing you to pipe clean data (JSON or text) from stdout while still capturing debug logs via stderr redirection to a file or separate stream.

### Can I use the verbose flag with JSON output mode?

Yes, the verbose flag functions independently of output formatting. When using `gogcli -v --json <command>`, debug logs write to stderr in text format while the command results print to stdout as JSON. This combination is useful for debugging API parsing issues while maintaining machine-readable output for downstream processing.