logging Library
code/logging is the shared logging package for the Go workspace. It wraps
Go’s log/slog with a process-global handler that can be reconfigured at
runtime, exposes named group loggers, and defaults timestamps to UTC.
Consumers: homelabctl2, proxmox-ipam. Both modules require it as
gitlab.com/joelMuehlena/homelab/code/logging; locally the workspace
(go.work) resolves it to the in-tree path, in CI a pseudo-version is
fetched from the GitLab module proxy.
import "gitlab.com/joelMuehlena/homelab/code/logging"
// At process startup (typically in main):logging.Init(logging.LOG_FORMAT_TEXT, logging.INFO)
// Adjust at runtime (e.g. after parsing --log-* flags):logging.SetLevel(logging.DEBUG)logging.SetFormat(logging.LOG_FORMAT_JSON)logging.SetTimezone(time.UTC) // default; takes any *time.Location
// Use it:log := logging.GetWithGroup("password-vault-init")log.Info("writing secret", "path", "secrets/data/foo", "keys", []string{"username"})| Function | Purpose |
|---|---|
Init(format, level) *slog.Logger | One-shot init. Second+ call warns and returns the existing logger. |
SetLevel(slog.Level) | Rebuild handler with new level (keeps format + tz). |
SetFormat(LogFormat) | Rebuild handler with new format (keeps level + tz). |
SetTimezone(*time.Location) | Rebuild handler so timestamps render in this zone. nil → UTC. |
Get() *slog.Logger | The root logger (no group). |
GetWithGroup(name) *slog.Logger | Root logger wrapped in WithGroup(name). |
LevelFromString(s) slog.Level | Parse debug / info / warning / error (falls back to info). |
FormatFromString(s) LogFormat | Parse text / json (falls back to text). |
Get() and GetWithGroup(name) return a snapshot of the configured
logger — call them inside the function that runs after SetLevel /
SetFormat / SetTimezone so the returned logger reflects the latest
config.
Defaults
Section titled “Defaults”| Aspect | Default |
|---|---|
| Level | WARN (until Init) / caller-chosen after Init |
| Format | caller-chosen (typically LOG_FORMAT_TEXT) |
| Timezone | time.UTC |
| Source | Added automatically when level is DEBUG |
| Output | os.Stdout |
Source attribution (file:line) is enabled when level < 0 (i.e. DEBUG)
so debug logs always include where they came from.
Wiring in homelabctl2
Section titled “Wiring in homelabctl2”homelabctl2’s main.go calls Init with text/info defaults so the
terminal-error path is usable even if cobra fails before
PersistentPreRunE. The root’s PersistentPreRunE then applies the parsed
--log-format / --log-level flags via SetFormat / SetLevel, plus
slog.SetDefault(logging.Get()) so any stray slog.* call also flows
through the configured handler. Timestamps stay UTC; no flag exposes it.
logging.Init(logging.LOG_FORMAT_TEXT, logging.INFO)if err := rootCmd.Execute(); err != nil { logging.Get().Error("command failed", "err", err) os.Exit(1)}
// cmd/homelabctl2/root.go (excerpt)PersistentPreRunE: func(_ *cobra.Command, _ []string) error { logging.SetFormat(logging.FormatFromString(logFormat)) logging.SetLevel(logging.LevelFromString(logLevel)) slog.SetDefault(logging.Get()) return nil}Subcommands obtain a named logger via logging.GetWithGroup("name") at
their entry function and plumb it to helpers that log:
func runPasswordVaultInit(cmd *cobra.Command, _ []string) error { log := logging.GetWithGroup("password-vault-init") // ... log.Info / log.Debug / log.Error ...}