ubgo is in early alpha: libraries and APIs may still change.

Skip to content
ubgo Alpha

Debug logs only when something breaks

FingersCrossed holds each request's debug lines back and writes them only if that request logs an error.

Based on the logger README, section “Debug-on-error (FingersCrossed)” About logger →

Step 1 of 7

A request gets its own buffer

The handler calls logger.FCScope(r.Context()). Every request now has its own buffer for log lines.

All steps as text
  1. A request gets its own buffer. The handler calls logger.FCScope(r.Context()). Every request now has its own buffer for log lines.
  2. A debug line is held back. log.DebugContext(ctx, "loaded config") goes into the request's buffer. Nothing is written to the sink yet.
  3. Another debug line. log.DebugContext(ctx, "queried db") joins it in the buffer. The sink is still empty.
  4. The request succeeds: silence. The request finishes without an error. A successful request logs nothing below the activation level, so neither debug line is ever written.
  5. A second request, same lines. The next request gets a fresh buffer and logs the same two debug lines. They wait in its buffer.
  6. This time an error is logged. log.ErrorContext(ctx, "boom") fires inside the request.
  7. The error flushes the whole trail. The first error flushes the buffer: both debug lines and the error are written. You get the full story exactly when something breaks.

The setup from the README:

fc := logger.NewFingersCrossed(
	logger.NewWriterSink(os.Stderr, logger.NewJSONEncoder(), logger.LevelTrace),
)
log := logger.New(logger.WithTransport(logger.NewSyncTransport(fc)), logger.WithLevel(logger.LevelTrace))

func handler(w http.ResponseWriter, r *http.Request) {
	ctx := logger.FCScope(r.Context()) // one buffer per request
	log.DebugContext(ctx, "loaded config")
	log.DebugContext(ctx, "queried db")
	// if everything succeeds → nothing is emitted
	// if log.ErrorContext(ctx, "boom") fires → the two Debug lines + the error are all flushed
}

The README calls this the killer feature: full detail when a request fails, and quiet logs when it does not.