Files
bible/rules/patterns/go-logging/contract.md
2026-03-01 17:16:50 +03:00

2.3 KiB

Contract: Logging (Go Web Applications)

Version: 1.0

Core Rule

All logging goes to the server binary's stdout/stderr — never to the browser console.

  • console.log, console.error, console.warn in JavaScript are for debugging only. Remove them before committing. They are not a substitute for server-side logging.
  • Diagnostic information (errors, slow queries, ingest results, background task status) must be logged server-side so it is visible in the terminal where the binary runs.

Go Logging Standard

Use the standard library log/slog (Go 1.21+) or log for simpler projects.

// correct — structured, visible in binary console
slog.Info("export started", "user", userID, "rows", count)
slog.Error("db query failed", "err", err)

// wrong — goes to browser devtools, invisible in production
// (JS template rendered in HTML)
// console.log("export started")

Log Levels

Level When to use
Debug Detailed flow tracing; disabled in production builds
Info Normal operation milestones: server start, request handled, export done
Warn Recoverable anomaly: retry, fallback used, deprecated path
Error Operation failed; always include "err", err as a structured attribute

What to Always Log

  • Server startup: address, port, config source.
  • Background task start/finish/error with task name and duration.
  • CSV/file export: scope, row count, duration.
  • Ingest/import: file name, rows accepted, rows rejected, error summary.
  • Any 500 response: handler name + error.

What Not to Log

  • Do not log full request bodies or CSV content — can contain PII or large payloads.
  • Do not log passwords, tokens, or secrets even partially.
  • Do not add fmt.Println for debugging and leave it in committed code.

htmx / Browser-rendered Responses

  • Handler errors that result in an htmx partial re-render must still log the error server-side.
  • Do not rely on the browser network tab as the only visibility into server errors.

Format

  • Use structured key-value attributes, not concatenated strings.
// correct
slog.Error("sync failed", "component", comp.Serial, "err", err)

// wrong — hard to grep, hard to parse
log.Printf("sync failed for component %s: %v", comp.Serial, err)