Scenario 2: Structured JSON Log Output
| Objective | Verify the fixed hcp CLI produces structured JSON log output with RFC3339 timestamps, consistent with hypershift-operator and control-plane-operator |
| Maps to | Acceptance criteria — structured JSON logging |
| Note | This is integration-level confirmation of what TestNewLogger already proves at unit level |
Result: PASS — Log output is valid JSON with RFC3339 timestamps, matching the pattern used by other HyperShift binaries.
Verification Steps
| Step | Check | Result | Evidence |
| 1 |
Run fixed binary and capture JSON log lines |
PASS |
JSON log line produced during destroy command |
| 2 |
Validate JSON structure |
PASS |
python3 -m json.tool confirms valid JSON |
| 3 |
Verify RFC3339 timestamp format |
PASS |
ts field = 2026-07-13T08:46:56-04:00 (RFC3339) |
| 4 |
Compare logger pattern with other binaries |
PASS |
Same zap.JSONEncoder + zapcore.RFC3339TimeEncoder pattern |
Evidence
Step 1: Fixed binary JSON log output
$ KUBECONFIG=/Users/brcox/aws_dev_kubeconfig /tmp/hcp-after destroy cluster azure \
--name nonexistent-cluster-78310 \
--azure-creds /Users/brcox/.azure/self-managed-azure-credentials.json \
--dns-zone-rg-name fake-rg 2>&1
{"level":"info","ts":"2026-07-13T08:46:56-04:00","msg":"Hosted cluster not found, destroying infrastructure from user input","namespace":"clusters","name":"nonexistent-cluster-78310","infraID":""}
Step 2: JSON validation
$ echo '{"level":"info","ts":"2026-07-13T08:46:56-04:00","msg":"Hosted cluster not found..."}' | python3 -m json.tool
VALID JSON
Step 3: RFC3339 timestamp verification
ts=2026-07-13T08:46:56-04:00 (RFC3339: True)
Step 4: Logger pattern comparison
--- hypershift-operator/main.go:118 ---
ctrl.SetLogger(zap.New(zap.JSONEncoder(func(o *zapcore.EncoderConfig) {
o.EncodeTime = zapcore.RFC3339TimeEncoder
})))
--- product-cli/main.go (fixed) ---
func newLogger(extraOpts ...zap.Opts) logr.Logger {
opts := []zap.Opts{zap.JSONEncoder(func(o *zapcore.EncoderConfig) {
o.EncodeTime = zapcore.RFC3339TimeEncoder
})}
opts = append(opts, extraOpts...)
return zap.New(opts...)
}