2.3 KiB
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.warnin 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
500response: 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.Printlnfor 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)