We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Minimal Logging

I've been encouraging you to log lots of useful context. So it may be surprising when I now tell you to log only what you absolutely must.

For security, the first line of defense is simple: don't log what you don't need.

Just Don't Log It

It should be obvious to not log passwords, API keys, and credit card numbers. Code like this often won't make it through a code review:

logger.Info("user attempting to authenticate",
	"name", username,
	"password", password,
)

What's much more likely is something like this:

logger.Info("connecting to database",
	"dsn", dsn,
)

This might look innocent in a 215-line pull request... but here's what it logs:

2024-01-15T10:30:45.123Z INFO msg="connecting to database" dsn="postgres://boots:[email protected]/backenddatabase"

Oops... now we're logging backend database credentials! That's why I use redaction helpers like this:

func safeDSN(dsn string) string {
	parsed, err := url.Parse(dsn)
	if err != nil {
		return "invalid dsn"
	}
	_, ok := parsed.User.Password()
	if !ok {
		return parsed.String()
	}
	parsed.User = url.UserPassword(parsed.User.Username(), "***")
	return parsed.String()
}

logger.Info("connecting to database",
	"dsn", safeDSN(dsn),
)
// 2024-01-15T10:30:45.123Z INFO msg="connecting to database" dsn="postgres://admin:***@db.example.com/appdb"

Don't Log Full Requests and Responses

While debugging, it's common to want to log full HTTP requests and responses. Resist that urge. They often contain sensitive data like API keys, cookies, and customer data.

req, _ := http.NewRequestWithContext(ctx, http.MethodGet, "https://bank.example.com/account/details", nil)
resp, _ := client.Do(req)
body, _ := io.ReadAll(resp.Body)
// DANGER: don't log the full URL/BODY -- there may be sensitive data in there!
logger.Debug("read API response from bank",
	"url", req.URL.String(),
	"body", string(body),
)

Instead, log only the minimum information you need.