slog: Handler.Enabled takes a context

Pass the Logger's context to its Handler's Enabled method,
so Enabled can use its values to make a decision.

Change-Id: Id1f77c5393a680dd4bfb462a5b6c9c9373e193ab
Reviewed-on: https://go-review.googlesource.com/c/exp/+/463935
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/slog/benchmarks/handlers.go b/slog/benchmarks/handlers.go
index ec40e58..0956929 100644
--- a/slog/benchmarks/handlers.go
+++ b/slog/benchmarks/handlers.go
@@ -7,6 +7,7 @@
 // Handlers for benchmarking.
 
 import (
+	"context"
 	"fmt"
 	"io"
 	"strconv"
@@ -31,7 +32,7 @@
 	return &fastTextHandler{w: w}
 }
 
-func (h *fastTextHandler) Enabled(slog.Level) bool { return true }
+func (h *fastTextHandler) Enabled(context.Context, slog.Level) bool { return true }
 
 func (h *fastTextHandler) Handle(r slog.Record) error {
 	buf := buffer.New()
@@ -116,7 +117,7 @@
 	return &asyncHandler{}
 }
 
-func (*asyncHandler) Enabled(slog.Level) bool { return true }
+func (*asyncHandler) Enabled(context.Context, slog.Level) bool { return true }
 
 func (h *asyncHandler) Handle(r slog.Record) error {
 	h.ringBuffer[h.next] = r.Clone()
@@ -134,8 +135,8 @@
 
 type disabledHandler struct{}
 
-func (disabledHandler) Enabled(slog.Level) bool  { return false }
-func (disabledHandler) Handle(slog.Record) error { panic("should not be called") }
+func (disabledHandler) Enabled(context.Context, slog.Level) bool { return false }
+func (disabledHandler) Handle(slog.Record) error                 { panic("should not be called") }
 
 func (disabledHandler) WithAttrs([]slog.Attr) slog.Handler {
 	panic("disabledHandler: With unimplemented")
diff --git a/slog/example_level_handler_test.go b/slog/example_level_handler_test.go
index 5374447..194f8d5 100644
--- a/slog/example_level_handler_test.go
+++ b/slog/example_level_handler_test.go
@@ -5,6 +5,7 @@
 package slog_test
 
 import (
+	"context"
 	"os"
 
 	"golang.org/x/exp/slog"
@@ -29,7 +30,7 @@
 
 // Enabled implements Handler.Enabled by reporting whether
 // level is at least as large as h's level.
-func (h *LevelHandler) Enabled(level slog.Level) bool {
+func (h *LevelHandler) Enabled(_ context.Context, level slog.Level) bool {
 	return level >= h.level.Level()
 }
 
diff --git a/slog/handler.go b/slog/handler.go
index 42edaf5..7c2a21b 100644
--- a/slog/handler.go
+++ b/slog/handler.go
@@ -5,6 +5,7 @@
 package slog
 
 import (
+	"context"
 	"fmt"
 	"io"
 	"strconv"
@@ -27,9 +28,11 @@
 type Handler interface {
 	// Enabled reports whether the handler handles records at the given level.
 	// The handler ignores records whose level is lower.
-	// Enabled is called early, before any arguments are processed,
+	// It is called early, before any arguments are processed,
 	// to save effort if the log event should be discarded.
-	Enabled(Level) bool
+	// The Logger's context is passed so Enabled can use its values
+	// to make a decision. The context may be nil.
+	Enabled(context.Context, Level) bool
 
 	// Handle handles the Record.
 	// It will only be called if Enabled returns true.
@@ -76,7 +79,7 @@
 	}
 }
 
-func (*defaultHandler) Enabled(l Level) bool {
+func (*defaultHandler) Enabled(_ context.Context, l Level) bool {
 	return l >= LevelInfo
 }
 
diff --git a/slog/json_handler.go b/slog/json_handler.go
index c373936..991a149 100644
--- a/slog/json_handler.go
+++ b/slog/json_handler.go
@@ -5,6 +5,7 @@
 package slog
 
 import (
+	"context"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -42,7 +43,7 @@
 
 // Enabled reports whether the handler handles records at the given level.
 // The handler ignores records whose level is lower.
-func (h *JSONHandler) Enabled(level Level) bool {
+func (h *JSONHandler) Enabled(_ context.Context, level Level) bool {
 	return h.commonHandler.enabled(level)
 }
 
diff --git a/slog/logger.go b/slog/logger.go
index 0f0c844..61dc933 100644
--- a/slog/logger.go
+++ b/slog/logger.go
@@ -45,7 +45,7 @@
 }
 
 func (w *handlerWriter) Write(buf []byte) (int, error) {
-	if !w.h.Enabled(LevelInfo) {
+	if !w.h.Enabled(nil, LevelInfo) {
 		return 0, nil
 	}
 	var pc uintptr
@@ -141,7 +141,7 @@
 
 // Enabled reports whether l emits log records at the given level.
 func (l *Logger) Enabled(level Level) bool {
-	return l.Handler().Enabled(level)
+	return l.Handler().Enabled(l.ctx, level)
 }
 
 // Log emits a log record with the current time and the given level and message.
diff --git a/slog/logger_test.go b/slog/logger_test.go
index 84380eb..766e123 100644
--- a/slog/logger_test.go
+++ b/slog/logger_test.go
@@ -137,7 +137,9 @@
 	h Handler
 }
 
-func (h wrappingHandler) Enabled(level Level) bool      { return h.h.Enabled(level) }
+func (h wrappingHandler) Enabled(ctx context.Context, level Level) bool {
+	return h.h.Enabled(ctx, level)
+}
 func (h wrappingHandler) WithGroup(name string) Handler { return h.h.WithGroup(name) }
 func (h wrappingHandler) WithAttrs(as []Attr) Handler   { return h.h.WithAttrs(as) }
 func (h wrappingHandler) Handle(r Record) error         { return h.h.Handle(r) }
@@ -438,7 +440,7 @@
 	return nil
 }
 
-func (*captureHandler) Enabled(Level) bool { return true }
+func (*captureHandler) Enabled(context.Context, Level) bool { return true }
 
 func (c *captureHandler) WithAttrs(as []Attr) Handler {
 	c2 := *c
@@ -457,8 +459,8 @@
 	attrs    []Attr
 }
 
-func (d discardHandler) Enabled(Level) bool { return !d.disabled }
-func (discardHandler) Handle(Record) error  { return nil }
+func (d discardHandler) Enabled(context.Context, Level) bool { return !d.disabled }
+func (discardHandler) Handle(Record) error                   { return nil }
 func (d discardHandler) WithAttrs(as []Attr) Handler {
 	d.attrs = concat(d.attrs, as)
 	return d
diff --git a/slog/text_handler.go b/slog/text_handler.go
index a91e8ac..f0fbeeb 100644
--- a/slog/text_handler.go
+++ b/slog/text_handler.go
@@ -5,6 +5,7 @@
 package slog
 
 import (
+	"context"
 	"encoding"
 	"fmt"
 	"io"
@@ -39,7 +40,7 @@
 
 // Enabled reports whether the handler handles records at the given level.
 // The handler ignores records whose level is lower.
-func (h *TextHandler) Enabled(level Level) bool {
+func (h *TextHandler) Enabled(_ context.Context, level Level) bool {
 	return h.commonHandler.enabled(level)
 }