slog: Loggers hold contexts

This CL provides a way to pass contexts to Handlers.

It is often asked that Handler.Handle be given access to the context
of the log line. The main reason is to allow logs to contain a trace
ID, so they can be correlated with tracing. Observability systems like
Open Telemetry store trace information in the context.

The usual suggestion is to add a context argument to log methods:

    slog.Info(ctx, "message")

But that imposes a burden on all users, even those who don't need
the context.

Another solution is to create a new Logger each time a new trace
element ("span" in Open Telemetry terminology) is created, with an
attribute containing the span (or the context). This means that
everyone who creates a span must remember to create a Logger as well,
or it requires wrapping this package in another, context-aware one.

This CL implements the following alternative:

- A Logger now holds a context as well as a Handler.

- Logger.Context returns this context.

- Logger.WithContext returns a new Logger with a given context.

- To avoid allocation in WithContext, Logger is changed from a pointer
  type to a value type. Since it is immutable, its semantics are
  unchanged. Its size is quadrupled (from a one-word pointer to a
  four-word struct); our benchmarks show small slowdowns for the
  fastest operations (that make unrealistically optimistic
  assumptions), and none for slower (and more practical) ones.

- Record has a new ctx field and a Context method to retrieve it.

- NewRecord gains an additional argument for the context.

- When a Logger l creates a Record r to pass to a Handler, it
  sets r.ctx to l.ctx.

- The top-level Ctx function both retrieves a Logger from a given
  context, and adds that context to the logger: it is equivalent to
      FromContext(ctx).WithContext(ctx)

Change-Id: I552b722c118d11406a05412e999c0b629b50228c
Reviewed-on: https://go-review.googlesource.com/c/exp/+/439059
Run-TryBot: Jonathan Amsterdam <jba@google.com>
Reviewed-by: Alan Donovan <adonovan@google.com>
12 files changed
tree: 1ba97f67779913c39a9e871575e6744dd9ea5230
  1. apidiff/
  2. cmd/
  3. constraints/
  4. devtools/
  5. ebnf/
  6. ebnflint/
  7. errors/
  8. event/
  9. inotify/
  10. io/
  11. jsonrpc2/
  12. maps/
  13. mmap/
  14. rand/
  15. shiny/
  16. shootout/
  17. slices/
  18. slog/
  19. sumdb/
  20. typeparams/
  21. utf8string/
  22. .gitattributes
  23. .gitignore
  24. codereview.cfg
  25. CONTRIBUTING.md
  26. go.mod
  27. go.sum
  28. LICENSE
  29. PATENTS
  30. README.md
README.md

exp

PkgGoDev

This subrepository holds experimental and deprecated (in the old directory) packages.

The idea for this subrepository originated as the pkg/exp directory of the main repository, but its presence there made it unavailable to users of the binary downloads of the Go installation. The subrepository has therefore been created to make it possible to go get these packages.

Warning: Packages here are experimental and unreliable. Some may one day be promoted to the main repository or other subrepository, or they may be modified arbitrarily or even disappear altogether.

In short, code in this subrepository is not subject to the Go 1 compatibility promise. (No subrepo is, but the promise is even more likely to be violated by go.exp than the others.)

Caveat emptor.