This guide provides information on how to debug the gac (Google Admin Client) application.
- Go 1.25+ installed
- Valid Google Workspace OAuth2 credentials
- Delve debugger installed (optional):
go install github.com/go-delve/delve/cmd/dlv@latest
Build the binary with debug symbols:
go build -gcflags="all=-N -l" -o gacOr use the Makefile:
make buildAdd debug print statements to track execution:
import "fmt"
func someFunction() {
fmt.Printf("DEBUG: variable value = %+v\n", variable)
}Start debugging with Delve:
# Debug the main package
dlv debug
# Debug with arguments
dlv debug -- user list
# Debug a specific test
dlv test ./cmd -- -test.run TestUserCreateCommon Delve commands:
break (b)- Set breakpointcontinue (c)- Continue executionnext (n)- Step overstep (s)- Step intoprint (p)- Print variablelist (l)- Show source codequit (q)- Exit debugger
Add this to .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug gac",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}",
"args": ["--help"]
},
{
"name": "Debug user list",
"type": "go",
"request": "launch",
"mode": "debug",
"program": "${workspaceFolder}",
"args": ["user", "list"]
},
{
"name": "Attach to Process",
"type": "go",
"request": "attach",
"mode": "local",
"processId": "${command:pickProcess}"
}
]
}- Set breakpoints by clicking in the gutter
- Right-click on
main.go→ Debug 'go build' - Configure run configurations with arguments
Enable verbose OAuth2 debugging:
// In cmd/client.go, add before creating HTTP client:
import "log"
import "net/http/httputil"
// Add request/response logging
client.Transport = &loggingTransport{http.DefaultTransport}
type loggingTransport struct {
rt http.RoundTripper
}
func (t *loggingTransport) RoundTrip(req *http.Request) (*http.Response, error) {
dump, _ := httputil.DumpRequest(req, true)
log.Printf("REQUEST:\n%s", dump)
resp, err := t.rt.RoundTrip(req)
if resp != nil {
dump, _ := httputil.DumpResponse(resp, true)
log.Printf("RESPONSE:\n%s", dump)
}
return resp, err
}Check the API response:
# Set verbose mode (if implemented)
./gac --verbose user list
# Check credential cache
cat ~/.credentials/gac.json | jq .
# Verify client secret
cat ~/.credentials/client_secret.json | jq .Debug configuration loading:
// In cmd/root.go, add to initConfig():
import "github.com/spf13/viper"
fmt.Printf("Config file used: %s\n", viper.ConfigFileUsed())
fmt.Printf("All settings: %+v\n", viper.AllSettings())Add retry logic with exponential backoff:
import "time"
import "google.golang.org/api/googleapi"
func retryableCall(fn func() error) error {
maxRetries := 3
for i := 0; i < maxRetries; i++ {
err := fn()
if err == nil {
return nil
}
if apiErr, ok := err.(*googleapi.Error); ok {
if apiErr.Code == 429 || apiErr.Code >= 500 {
backoff := time.Duration(1<<uint(i)) * time.Second
fmt.Printf("Retrying after %v (attempt %d/%d)\n", backoff, i+1, maxRetries)
time.Sleep(backoff)
continue
}
}
return err
}
return fmt.Errorf("max retries exceeded")
}Run tests with verbose output:
# Run all tests verbosely
go test -v ./...
# Run specific test
go test -v ./cmd -run TestUserCreate
# Run with race detector
go test -race ./...
# Generate coverage
go test -coverprofile=coverage.out ./...
go tool cover -html=coverage.outSet these for debugging:
# Enable Go debugging
export GODEBUG=gctrace=1
# HTTP debugging
export GODEBUG=http2debug=1
# Disable HTTP/2
export GODEBUG=http2client=0- Check if
client_secret.jsonexists in~/.credentials/ - Verify the JSON format is valid
- Ensure OAuth2 scopes are correct
- Delete cached token:
rm ~/.credentials/gac.json - Re-authenticate:
./gac init -f
- Verify the Google Workspace admin account has necessary permissions
- Check OAuth2 scopes include required permissions
- Review Google Admin Console → Security → API Controls
# Clean and rebuild
make clean
make build
# Update dependencies
go mod tidy
go mod downloadAdd structured logging (future enhancement):
import "log/slog"
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
logger.Info("User operation", "email", email, "action", "create")Profile CPU usage:
go build -o gac
./gac --cpuprofile=cpu.prof user list
go tool pprof cpu.profProfile memory usage:
go build -o gac
./gac --memprofile=mem.prof user list
go tool pprof mem.prof