Reason/Context
The entire microcks-cli codebase uses fmt.Printf/fmt.Println for all output — command results, error messages, HTTP dumps, and diagnostic messages all go to stdout indiscriminately. This creates three concrete production problems:
1. CI/CD pipelines cannot parse command output
Commands like import print "Microcks has discovered 'foo'" mixed with "Got error when invoking..." on the same stdout stream. There is no way to reliably extract machine-readable results without brittle text parsing.
2. Verbose mode leaks secrets (issue #265)
--verbose dumps full HTTP request/response bodies including Bearer tokens and Basic auth credentials to stdout. There is no way to enable HTTP debugging without exposing credentials — it is binary: silent or everything.
3. Diagnostic output contaminates command output
POSIX convention: command results go to stdout, diagnostic messages go to stderr. The CLI mixes both on stdout, making it impossible to pipe command output (microcks test ... | jq .) without also receiving error messages in the pipe.
Go 1.21 introduced log/slog — structured, leveled logging in the standard library. This project uses Go 1.25. The fix is available in stdlib with zero new dependencies.
Description
Adopt log/slog across the codebase to establish a proper separation between command output and diagnostic output.
New --log-level flag replacing the binary --verbose:
error — only fatal errors
info — normal command progress (current default behavior)
debug — HTTP request/response dumps, token exchange details (current --verbose)
Redaction at the handler level:
A custom slog.Handler wraps the default handler and redacts fields matching Authorization, token, secret, password — resolving issue #265 permanently regardless of log level.
Stdout vs Stderr separation:
All slog output routes to os.Stderr. All structured command results route to os.Stdout. This enables:
microcks test ... --output json 2>/dev/null | jq '.success'
microcks test ... --log-level debug 2>debug.log
Non-breaking: --verbose becomes a deprecated alias for --log-level=debug. Default behavior unchanged.
Implementation ideas
Initialize slog in cmd/cmd.go PersistentPreRun:
var logLevel slog.LevelVar
handler := slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{
Level: &logLevel,
})
slog.SetDefault(slog.New(NewRedactingHandler(handler)))
Custom redacting handler (stdlib only — zero new dependencies):
type RedactingHandler struct{ inner slog.Handler }
func (h *RedactingHandler) Handle(ctx context.Context, r slog.Record) error {
r.Attrs(func(a slog.Attr) bool {
if isSecret(a.Key) {
a.Value = slog.StringValue("[REDACTED]")
}
return true
})
return h.inner.Handle(ctx, r)
}
Replacements throughout codebase:
fmt.Printf("Got error: %s", err) → slog.Error("operation failed", "error", err)
fmt.Printf("Callback: %s", r.URL) → slog.Debug("oauth callback", "url", r.URL)
log.Printf("Token: %s", token) → removed (was issue #345)
Files affected: cmd/*.go, pkg/connectors/microcks_client.go, pkg/connectors/keycloak_client.go
New dependencies: zero — log/slog is stdlib since Go 1.21
Issues this resolves: #265, #345, #373, #387
Reason/Context
The entire microcks-cli codebase uses
fmt.Printf/fmt.Printlnfor all output — command results, error messages, HTTP dumps, and diagnostic messages all go to stdout indiscriminately. This creates three concrete production problems:1. CI/CD pipelines cannot parse command output
Commands like
importprint"Microcks has discovered 'foo'"mixed with"Got error when invoking..."on the same stdout stream. There is no way to reliably extract machine-readable results without brittle text parsing.2. Verbose mode leaks secrets (issue #265)
--verbosedumps full HTTP request/response bodies including Bearer tokens and Basic auth credentials to stdout. There is no way to enable HTTP debugging without exposing credentials — it is binary: silent or everything.3. Diagnostic output contaminates command output
POSIX convention: command results go to stdout, diagnostic messages go to stderr. The CLI mixes both on stdout, making it impossible to pipe command output (
microcks test ... | jq .) without also receiving error messages in the pipe.Go 1.21 introduced
log/slog— structured, leveled logging in the standard library. This project uses Go 1.25. The fix is available in stdlib with zero new dependencies.Description
Adopt
log/slogacross the codebase to establish a proper separation between command output and diagnostic output.New
--log-levelflag replacing the binary--verbose:error— only fatal errorsinfo— normal command progress (current default behavior)debug— HTTP request/response dumps, token exchange details (current--verbose)Redaction at the handler level:
A custom
slog.Handlerwraps the default handler and redacts fields matchingAuthorization,token,secret,password— resolving issue #265 permanently regardless of log level.Stdout vs Stderr separation:
All
slogoutput routes toos.Stderr. All structured command results route toos.Stdout. This enables:microcks test ... --output json 2>/dev/null | jq '.success'microcks test ... --log-level debug 2>debug.logNon-breaking:
--verbosebecomes a deprecated alias for--log-level=debug. Default behavior unchanged.Implementation ideas
Initialize slog in
cmd/cmd.goPersistentPreRun: