summaryrefslogtreecommitdiff
path: root/vendor/golang.org/x/exp/slog
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-01-17 14:54:30 +0000
committerLibravatar GitHub <noreply@github.com>2024-01-17 14:54:30 +0000
commit906639ad7eb92e9d631599f78979908930e59c84 (patch)
treedfef6d0a5ba47c49c214e4537a89dee6ad528df8 /vendor/golang.org/x/exp/slog
parent[bugfix] Better Postgres search case insensitivity (#2526) (diff)
downloadgotosocial-906639ad7eb92e9d631599f78979908930e59c84.tar.xz
[chore] update viper version (#2539)
* update viper version * removes our last uses of the slice package * fix tests
Diffstat (limited to 'vendor/golang.org/x/exp/slog')
-rw-r--r--vendor/golang.org/x/exp/slog/attr.go102
-rw-r--r--vendor/golang.org/x/exp/slog/doc.go316
-rw-r--r--vendor/golang.org/x/exp/slog/handler.go577
-rw-r--r--vendor/golang.org/x/exp/slog/internal/buffer/buffer.go84
-rw-r--r--vendor/golang.org/x/exp/slog/internal/ignorepc.go9
-rw-r--r--vendor/golang.org/x/exp/slog/json_handler.go336
-rw-r--r--vendor/golang.org/x/exp/slog/level.go201
-rw-r--r--vendor/golang.org/x/exp/slog/logger.go343
-rw-r--r--vendor/golang.org/x/exp/slog/noplog.bench36
-rw-r--r--vendor/golang.org/x/exp/slog/record.go207
-rw-r--r--vendor/golang.org/x/exp/slog/text_handler.go161
-rw-r--r--vendor/golang.org/x/exp/slog/value.go456
-rw-r--r--vendor/golang.org/x/exp/slog/value_119.go53
-rw-r--r--vendor/golang.org/x/exp/slog/value_120.go39
14 files changed, 2920 insertions, 0 deletions
diff --git a/vendor/golang.org/x/exp/slog/attr.go b/vendor/golang.org/x/exp/slog/attr.go
new file mode 100644
index 000000000..a180d0e1d
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/attr.go
@@ -0,0 +1,102 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "fmt"
+ "time"
+)
+
+// An Attr is a key-value pair.
+type Attr struct {
+ Key string
+ Value Value
+}
+
+// String returns an Attr for a string value.
+func String(key, value string) Attr {
+ return Attr{key, StringValue(value)}
+}
+
+// Int64 returns an Attr for an int64.
+func Int64(key string, value int64) Attr {
+ return Attr{key, Int64Value(value)}
+}
+
+// Int converts an int to an int64 and returns
+// an Attr with that value.
+func Int(key string, value int) Attr {
+ return Int64(key, int64(value))
+}
+
+// Uint64 returns an Attr for a uint64.
+func Uint64(key string, v uint64) Attr {
+ return Attr{key, Uint64Value(v)}
+}
+
+// Float64 returns an Attr for a floating-point number.
+func Float64(key string, v float64) Attr {
+ return Attr{key, Float64Value(v)}
+}
+
+// Bool returns an Attr for a bool.
+func Bool(key string, v bool) Attr {
+ return Attr{key, BoolValue(v)}
+}
+
+// Time returns an Attr for a time.Time.
+// It discards the monotonic portion.
+func Time(key string, v time.Time) Attr {
+ return Attr{key, TimeValue(v)}
+}
+
+// Duration returns an Attr for a time.Duration.
+func Duration(key string, v time.Duration) Attr {
+ return Attr{key, DurationValue(v)}
+}
+
+// Group returns an Attr for a Group Value.
+// The first argument is the key; the remaining arguments
+// are converted to Attrs as in [Logger.Log].
+//
+// Use Group to collect several key-value pairs under a single
+// key on a log line, or as the result of LogValue
+// in order to log a single value as multiple Attrs.
+func Group(key string, args ...any) Attr {
+ return Attr{key, GroupValue(argsToAttrSlice(args)...)}
+}
+
+func argsToAttrSlice(args []any) []Attr {
+ var (
+ attr Attr
+ attrs []Attr
+ )
+ for len(args) > 0 {
+ attr, args = argsToAttr(args)
+ attrs = append(attrs, attr)
+ }
+ return attrs
+}
+
+// Any returns an Attr for the supplied value.
+// See [Value.AnyValue] for how values are treated.
+func Any(key string, value any) Attr {
+ return Attr{key, AnyValue(value)}
+}
+
+// Equal reports whether a and b have equal keys and values.
+func (a Attr) Equal(b Attr) bool {
+ return a.Key == b.Key && a.Value.Equal(b.Value)
+}
+
+func (a Attr) String() string {
+ return fmt.Sprintf("%s=%s", a.Key, a.Value)
+}
+
+// isEmpty reports whether a has an empty key and a nil value.
+// That can be written as Attr{} or Any("", nil).
+func (a Attr) isEmpty() bool {
+ return a.Key == "" && a.Value.num == 0 && a.Value.any == nil
+}
diff --git a/vendor/golang.org/x/exp/slog/doc.go b/vendor/golang.org/x/exp/slog/doc.go
new file mode 100644
index 000000000..4beaf8674
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/doc.go
@@ -0,0 +1,316 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package slog provides structured logging,
+in which log records include a message,
+a severity level, and various other attributes
+expressed as key-value pairs.
+
+It defines a type, [Logger],
+which provides several methods (such as [Logger.Info] and [Logger.Error])
+for reporting events of interest.
+
+Each Logger is associated with a [Handler].
+A Logger output method creates a [Record] from the method arguments
+and passes it to the Handler, which decides how to handle it.
+There is a default Logger accessible through top-level functions
+(such as [Info] and [Error]) that call the corresponding Logger methods.
+
+A log record consists of a time, a level, a message, and a set of key-value
+pairs, where the keys are strings and the values may be of any type.
+As an example,
+
+ slog.Info("hello", "count", 3)
+
+creates a record containing the time of the call,
+a level of Info, the message "hello", and a single
+pair with key "count" and value 3.
+
+The [Info] top-level function calls the [Logger.Info] method on the default Logger.
+In addition to [Logger.Info], there are methods for Debug, Warn and Error levels.
+Besides these convenience methods for common levels,
+there is also a [Logger.Log] method which takes the level as an argument.
+Each of these methods has a corresponding top-level function that uses the
+default logger.
+
+The default handler formats the log record's message, time, level, and attributes
+as a string and passes it to the [log] package.
+
+ 2022/11/08 15:28:26 INFO hello count=3
+
+For more control over the output format, create a logger with a different handler.
+This statement uses [New] to create a new logger with a TextHandler
+that writes structured records in text form to standard error:
+
+ logger := slog.New(slog.NewTextHandler(os.Stderr, nil))
+
+[TextHandler] output is a sequence of key=value pairs, easily and unambiguously
+parsed by machine. This statement:
+
+ logger.Info("hello", "count", 3)
+
+produces this output:
+
+ time=2022-11-08T15:28:26.000-05:00 level=INFO msg=hello count=3
+
+The package also provides [JSONHandler], whose output is line-delimited JSON:
+
+ logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
+ logger.Info("hello", "count", 3)
+
+produces this output:
+
+ {"time":"2022-11-08T15:28:26.000000000-05:00","level":"INFO","msg":"hello","count":3}
+
+Both [TextHandler] and [JSONHandler] can be configured with [HandlerOptions].
+There are options for setting the minimum level (see Levels, below),
+displaying the source file and line of the log call, and
+modifying attributes before they are logged.
+
+Setting a logger as the default with
+
+ slog.SetDefault(logger)
+
+will cause the top-level functions like [Info] to use it.
+[SetDefault] also updates the default logger used by the [log] package,
+so that existing applications that use [log.Printf] and related functions
+will send log records to the logger's handler without needing to be rewritten.
+
+Some attributes are common to many log calls.
+For example, you may wish to include the URL or trace identifier of a server request
+with all log events arising from the request.
+Rather than repeat the attribute with every log call, you can use [Logger.With]
+to construct a new Logger containing the attributes:
+
+ logger2 := logger.With("url", r.URL)
+
+The arguments to With are the same key-value pairs used in [Logger.Info].
+The result is a new Logger with the same handler as the original, but additional
+attributes that will appear in the output of every call.
+
+# Levels
+
+A [Level] is an integer representing the importance or severity of a log event.
+The higher the level, the more severe the event.
+This package defines constants for the most common levels,
+but any int can be used as a level.
+
+In an application, you may wish to log messages only at a certain level or greater.
+One common configuration is to log messages at Info or higher levels,
+suppressing debug logging until it is needed.
+The built-in handlers can be configured with the minimum level to output by
+setting [HandlerOptions.Level].
+The program's `main` function typically does this.
+The default value is LevelInfo.
+
+Setting the [HandlerOptions.Level] field to a [Level] value
+fixes the handler's minimum level throughout its lifetime.
+Setting it to a [LevelVar] allows the level to be varied dynamically.
+A LevelVar holds a Level and is safe to read or write from multiple
+goroutines.
+To vary the level dynamically for an entire program, first initialize
+a global LevelVar:
+
+ var programLevel = new(slog.LevelVar) // Info by default
+
+Then use the LevelVar to construct a handler, and make it the default:
+
+ h := slog.NewJSONHandler(os.Stderr, &slog.HandlerOptions{Level: programLevel})
+ slog.SetDefault(slog.New(h))
+
+Now the program can change its logging level with a single statement:
+
+ programLevel.Set(slog.LevelDebug)
+
+# Groups
+
+Attributes can be collected into groups.
+A group has a name that is used to qualify the names of its attributes.
+How this qualification is displayed depends on the handler.
+[TextHandler] separates the group and attribute names with a dot.
+[JSONHandler] treats each group as a separate JSON object, with the group name as the key.
+
+Use [Group] to create a Group attribute from a name and a list of key-value pairs:
+
+ slog.Group("request",
+ "method", r.Method,
+ "url", r.URL)
+
+TextHandler would display this group as
+
+ request.method=GET request.url=http://example.com
+
+JSONHandler would display it as
+
+ "request":{"method":"GET","url":"http://example.com"}
+
+Use [Logger.WithGroup] to qualify all of a Logger's output
+with a group name. Calling WithGroup on a Logger results in a
+new Logger with the same Handler as the original, but with all
+its attributes qualified by the group name.
+
+This can help prevent duplicate attribute keys in large systems,
+where subsystems might use the same keys.
+Pass each subsystem a different Logger with its own group name so that
+potential duplicates are qualified:
+
+ logger := slog.Default().With("id", systemID)
+ parserLogger := logger.WithGroup("parser")
+ parseInput(input, parserLogger)
+
+When parseInput logs with parserLogger, its keys will be qualified with "parser",
+so even if it uses the common key "id", the log line will have distinct keys.
+
+# Contexts
+
+Some handlers may wish to include information from the [context.Context] that is
+available at the call site. One example of such information
+is the identifier for the current span when tracing is enabled.
+
+The [Logger.Log] and [Logger.LogAttrs] methods take a context as a first
+argument, as do their corresponding top-level functions.
+
+Although the convenience methods on Logger (Info and so on) and the
+corresponding top-level functions do not take a context, the alternatives ending
+in "Context" do. For example,
+
+ slog.InfoContext(ctx, "message")
+
+It is recommended to pass a context to an output method if one is available.
+
+# Attrs and Values
+
+An [Attr] is a key-value pair. The Logger output methods accept Attrs as well as
+alternating keys and values. The statement
+
+ slog.Info("hello", slog.Int("count", 3))
+
+behaves the same as
+
+ slog.Info("hello", "count", 3)
+
+There are convenience constructors for [Attr] such as [Int], [String], and [Bool]
+for common types, as well as the function [Any] for constructing Attrs of any
+type.
+
+The value part of an Attr is a type called [Value].
+Like an [any], a Value can hold any Go value,
+but it can represent typical values, including all numbers and strings,
+without an allocation.
+
+For the most efficient log output, use [Logger.LogAttrs].
+It is similar to [Logger.Log] but accepts only Attrs, not alternating
+keys and values; this allows it, too, to avoid allocation.
+
+The call
+
+ logger.LogAttrs(nil, slog.LevelInfo, "hello", slog.Int("count", 3))
+
+is the most efficient way to achieve the same output as
+
+ slog.Info("hello", "count", 3)
+
+# Customizing a type's logging behavior
+
+If a type implements the [LogValuer] interface, the [Value] returned from its LogValue
+method is used for logging. You can use this to control how values of the type
+appear in logs. For example, you can redact secret information like passwords,
+or gather a struct's fields in a Group. See the examples under [LogValuer] for
+details.
+
+A LogValue method may return a Value that itself implements [LogValuer]. The [Value.Resolve]
+method handles these cases carefully, avoiding infinite loops and unbounded recursion.
+Handler authors and others may wish to use Value.Resolve instead of calling LogValue directly.
+
+# Wrapping output methods
+
+The logger functions use reflection over the call stack to find the file name
+and line number of the logging call within the application. This can produce
+incorrect source information for functions that wrap slog. For instance, if you
+define this function in file mylog.go:
+
+ func Infof(format string, args ...any) {
+ slog.Default().Info(fmt.Sprintf(format, args...))
+ }
+
+and you call it like this in main.go:
+
+ Infof(slog.Default(), "hello, %s", "world")
+
+then slog will report the source file as mylog.go, not main.go.
+
+A correct implementation of Infof will obtain the source location
+(pc) and pass it to NewRecord.
+The Infof function in the package-level example called "wrapping"
+demonstrates how to do this.
+
+# Working with Records
+
+Sometimes a Handler will need to modify a Record
+before passing it on to another Handler or backend.
+A Record contains a mixture of simple public fields (e.g. Time, Level, Message)
+and hidden fields that refer to state (such as attributes) indirectly. This
+means that modifying a simple copy of a Record (e.g. by calling
+[Record.Add] or [Record.AddAttrs] to add attributes)
+may have unexpected effects on the original.
+Before modifying a Record, use [Clone] to
+create a copy that shares no state with the original,
+or create a new Record with [NewRecord]
+and build up its Attrs by traversing the old ones with [Record.Attrs].
+
+# Performance considerations
+
+If profiling your application demonstrates that logging is taking significant time,
+the following suggestions may help.
+
+If many log lines have a common attribute, use [Logger.With] to create a Logger with
+that attribute. The built-in handlers will format that attribute only once, at the
+call to [Logger.With]. The [Handler] interface is designed to allow that optimization,
+and a well-written Handler should take advantage of it.
+
+The arguments to a log call are always evaluated, even if the log event is discarded.
+If possible, defer computation so that it happens only if the value is actually logged.
+For example, consider the call
+
+ slog.Info("starting request", "url", r.URL.String()) // may compute String unnecessarily
+
+The URL.String method will be called even if the logger discards Info-level events.
+Instead, pass the URL directly:
+
+ slog.Info("starting request", "url", &r.URL) // calls URL.String only if needed
+
+The built-in [TextHandler] will call its String method, but only
+if the log event is enabled.
+Avoiding the call to String also preserves the structure of the underlying value.
+For example [JSONHandler] emits the components of the parsed URL as a JSON object.
+If you want to avoid eagerly paying the cost of the String call
+without causing the handler to potentially inspect the structure of the value,
+wrap the value in a fmt.Stringer implementation that hides its Marshal methods.
+
+You can also use the [LogValuer] interface to avoid unnecessary work in disabled log
+calls. Say you need to log some expensive value:
+
+ slog.Debug("frobbing", "value", computeExpensiveValue(arg))
+
+Even if this line is disabled, computeExpensiveValue will be called.
+To avoid that, define a type implementing LogValuer:
+
+ type expensive struct { arg int }
+
+ func (e expensive) LogValue() slog.Value {
+ return slog.AnyValue(computeExpensiveValue(e.arg))
+ }
+
+Then use a value of that type in log calls:
+
+ slog.Debug("frobbing", "value", expensive{arg})
+
+Now computeExpensiveValue will only be called when the line is enabled.
+
+The built-in handlers acquire a lock before calling [io.Writer.Write]
+to ensure that each record is written in one piece. User-defined
+handlers are responsible for their own locking.
+*/
+package slog
diff --git a/vendor/golang.org/x/exp/slog/handler.go b/vendor/golang.org/x/exp/slog/handler.go
new file mode 100644
index 000000000..bd635cb81
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/handler.go
@@ -0,0 +1,577 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "sync"
+ "time"
+
+ "golang.org/x/exp/slices"
+ "golang.org/x/exp/slog/internal/buffer"
+)
+
+// A Handler handles log records produced by a Logger..
+//
+// A typical handler may print log records to standard error,
+// or write them to a file or database, or perhaps augment them
+// with additional attributes and pass them on to another handler.
+//
+// Any of the Handler's methods may be called concurrently with itself
+// or with other methods. It is the responsibility of the Handler to
+// manage this concurrency.
+//
+// Users of the slog package should not invoke Handler methods directly.
+// They should use the methods of [Logger] instead.
+type Handler interface {
+ // Enabled reports whether the handler handles records at the given level.
+ // The handler ignores records whose level is lower.
+ // It is called early, before any arguments are processed,
+ // to save effort if the log event should be discarded.
+ // If called from a Logger method, the first argument is the context
+ // passed to that method, or context.Background() if nil was passed
+ // or the method does not take a context.
+ // The context is passed so Enabled can use its values
+ // to make a decision.
+ Enabled(context.Context, Level) bool
+
+ // Handle handles the Record.
+ // It will only be called when Enabled returns true.
+ // The Context argument is as for Enabled.
+ // It is present solely to provide Handlers access to the context's values.
+ // Canceling the context should not affect record processing.
+ // (Among other things, log messages may be necessary to debug a
+ // cancellation-related problem.)
+ //
+ // Handle methods that produce output should observe the following rules:
+ // - If r.Time is the zero time, ignore the time.
+ // - If r.PC is zero, ignore it.
+ // - Attr's values should be resolved.
+ // - If an Attr's key and value are both the zero value, ignore the Attr.
+ // This can be tested with attr.Equal(Attr{}).
+ // - If a group's key is empty, inline the group's Attrs.
+ // - If a group has no Attrs (even if it has a non-empty key),
+ // ignore it.
+ Handle(context.Context, Record) error
+
+ // WithAttrs returns a new Handler whose attributes consist of
+ // both the receiver's attributes and the arguments.
+ // The Handler owns the slice: it may retain, modify or discard it.
+ WithAttrs(attrs []Attr) Handler
+
+ // WithGroup returns a new Handler with the given group appended to
+ // the receiver's existing groups.
+ // The keys of all subsequent attributes, whether added by With or in a
+ // Record, should be qualified by the sequence of group names.
+ //
+ // How this qualification happens is up to the Handler, so long as
+ // this Handler's attribute keys differ from those of another Handler
+ // with a different sequence of group names.
+ //
+ // A Handler should treat WithGroup as starting a Group of Attrs that ends
+ // at the end of the log event. That is,
+ //
+ // logger.WithGroup("s").LogAttrs(level, msg, slog.Int("a", 1), slog.Int("b", 2))
+ //
+ // should behave like
+ //
+ // logger.LogAttrs(level, msg, slog.Group("s", slog.Int("a", 1), slog.Int("b", 2)))
+ //
+ // If the name is empty, WithGroup returns the receiver.
+ WithGroup(name string) Handler
+}
+
+type defaultHandler struct {
+ ch *commonHandler
+ // log.Output, except for testing
+ output func(calldepth int, message string) error
+}
+
+func newDefaultHandler(output func(int, string) error) *defaultHandler {
+ return &defaultHandler{
+ ch: &commonHandler{json: false},
+ output: output,
+ }
+}
+
+func (*defaultHandler) Enabled(_ context.Context, l Level) bool {
+ return l >= LevelInfo
+}
+
+// Collect the level, attributes and message in a string and
+// write it with the default log.Logger.
+// Let the log.Logger handle time and file/line.
+func (h *defaultHandler) Handle(ctx context.Context, r Record) error {
+ buf := buffer.New()
+ buf.WriteString(r.Level.String())
+ buf.WriteByte(' ')
+ buf.WriteString(r.Message)
+ state := h.ch.newHandleState(buf, true, " ", nil)
+ defer state.free()
+ state.appendNonBuiltIns(r)
+
+ // skip [h.output, defaultHandler.Handle, handlerWriter.Write, log.Output]
+ return h.output(4, buf.String())
+}
+
+func (h *defaultHandler) WithAttrs(as []Attr) Handler {
+ return &defaultHandler{h.ch.withAttrs(as), h.output}
+}
+
+func (h *defaultHandler) WithGroup(name string) Handler {
+ return &defaultHandler{h.ch.withGroup(name), h.output}
+}
+
+// HandlerOptions are options for a TextHandler or JSONHandler.
+// A zero HandlerOptions consists entirely of default values.
+type HandlerOptions struct {
+ // AddSource causes the handler to compute the source code position
+ // of the log statement and add a SourceKey attribute to the output.
+ AddSource bool
+
+ // Level reports the minimum record level that will be logged.
+ // The handler discards records with lower levels.
+ // If Level is nil, the handler assumes LevelInfo.
+ // The handler calls Level.Level for each record processed;
+ // to adjust the minimum level dynamically, use a LevelVar.
+ Level Leveler
+
+ // ReplaceAttr is called to rewrite each non-group attribute before it is logged.
+ // The attribute's value has been resolved (see [Value.Resolve]).
+ // If ReplaceAttr returns an Attr with Key == "", the attribute is discarded.
+ //
+ // The built-in attributes with keys "time", "level", "source", and "msg"
+ // are passed to this function, except that time is omitted
+ // if zero, and source is omitted if AddSource is false.
+ //
+ // The first argument is a list of currently open groups that contain the
+ // Attr. It must not be retained or modified. ReplaceAttr is never called
+ // for Group attributes, only their contents. For example, the attribute
+ // list
+ //
+ // Int("a", 1), Group("g", Int("b", 2)), Int("c", 3)
+ //
+ // results in consecutive calls to ReplaceAttr with the following arguments:
+ //
+ // nil, Int("a", 1)
+ // []string{"g"}, Int("b", 2)
+ // nil, Int("c", 3)
+ //
+ // ReplaceAttr can be used to change the default keys of the built-in
+ // attributes, convert types (for example, to replace a `time.Time` with the
+ // integer seconds since the Unix epoch), sanitize personal information, or
+ // remove attributes from the output.
+ ReplaceAttr func(groups []string, a Attr) Attr
+}
+
+// Keys for "built-in" attributes.
+const (
+ // TimeKey is the key used by the built-in handlers for the time
+ // when the log method is called. The associated Value is a [time.Time].
+ TimeKey = "time"
+ // LevelKey is the key used by the built-in handlers for the level
+ // of the log call. The associated value is a [Level].
+ LevelKey = "level"
+ // MessageKey is the key used by the built-in handlers for the
+ // message of the log call. The associated value is a string.
+ MessageKey = "msg"
+ // SourceKey is the key used by the built-in handlers for the source file
+ // and line of the log call. The associated value is a string.
+ SourceKey = "source"
+)
+
+type commonHandler struct {
+ json bool // true => output JSON; false => output text
+ opts HandlerOptions
+ preformattedAttrs []byte
+ groupPrefix string // for text: prefix of groups opened in preformatting
+ groups []string // all groups started from WithGroup
+ nOpenGroups int // the number of groups opened in preformattedAttrs
+ mu sync.Mutex
+ w io.Writer
+}
+
+func (h *commonHandler) clone() *commonHandler {
+ // We can't use assignment because we can't copy the mutex.
+ return &commonHandler{
+ json: h.json,
+ opts: h.opts,
+ preformattedAttrs: slices.Clip(h.preformattedAttrs),
+ groupPrefix: h.groupPrefix,
+ groups: slices.Clip(h.groups),
+ nOpenGroups: h.nOpenGroups,
+ w: h.w,
+ }
+}
+
+// enabled reports whether l is greater than or equal to the
+// minimum level.
+func (h *commonHandler) enabled(l Level) bool {
+ minLevel := LevelInfo
+ if h.opts.Level != nil {
+ minLevel = h.opts.Level.Level()
+ }
+ return l >= minLevel
+}
+
+func (h *commonHandler) withAttrs(as []Attr) *commonHandler {
+ h2 := h.clone()
+ // Pre-format the attributes as an optimization.
+ prefix := buffer.New()
+ defer prefix.Free()
+ prefix.WriteString(h.groupPrefix)
+ state := h2.newHandleState((*buffer.Buffer)(&h2.preformattedAttrs), false, "", prefix)
+ defer state.free()
+ if len(h2.preformattedAttrs) > 0 {
+ state.sep = h.attrSep()
+ }
+ state.openGroups()
+ for _, a := range as {
+ state.appendAttr(a)
+ }
+ // Remember the new prefix for later keys.
+ h2.groupPrefix = state.prefix.String()
+ // Remember how many opened groups are in preformattedAttrs,
+ // so we don't open them again when we handle a Record.
+ h2.nOpenGroups = len(h2.groups)
+ return h2
+}
+
+func (h *commonHandler) withGroup(name string) *commonHandler {
+ if name == "" {
+ return h
+ }
+ h2 := h.clone()
+ h2.groups = append(h2.groups, name)
+ return h2
+}
+
+func (h *commonHandler) handle(r Record) error {
+ state := h.newHandleState(buffer.New(), true, "", nil)
+ defer state.free()
+ if h.json {
+ state.buf.WriteByte('{')
+ }
+ // Built-in attributes. They are not in a group.
+ stateGroups := state.groups
+ state.groups = nil // So ReplaceAttrs sees no groups instead of the pre groups.
+ rep := h.opts.ReplaceAttr
+ // time
+ if !r.Time.IsZero() {
+ key := TimeKey
+ val := r.Time.Round(0) // strip monotonic to match Attr behavior
+ if rep == nil {
+ state.appendKey(key)
+ state.appendTime(val)
+ } else {
+ state.appendAttr(Time(key, val))
+ }
+ }
+ // level
+ key := LevelKey
+ val := r.Level
+ if rep == nil {
+ state.appendKey(key)
+ state.appendString(val.String())
+ } else {
+ state.appendAttr(Any(key, val))
+ }
+ // source
+ if h.opts.AddSource {
+ state.appendAttr(Any(SourceKey, r.source()))
+ }
+ key = MessageKey
+ msg := r.Message
+ if rep == nil {
+ state.appendKey(key)
+ state.appendString(msg)
+ } else {
+ state.appendAttr(String(key, msg))
+ }
+ state.groups = stateGroups // Restore groups passed to ReplaceAttrs.
+ state.appendNonBuiltIns(r)
+ state.buf.WriteByte('\n')
+
+ h.mu.Lock()
+ defer h.mu.Unlock()
+ _, err := h.w.Write(*state.buf)
+ return err
+}
+
+func (s *handleState) appendNonBuiltIns(r Record) {
+ // preformatted Attrs
+ if len(s.h.preformattedAttrs) > 0 {
+ s.buf.WriteString(s.sep)
+ s.buf.Write(s.h.preformattedAttrs)
+ s.sep = s.h.attrSep()
+ }
+ // Attrs in Record -- unlike the built-in ones, they are in groups started
+ // from WithGroup.
+ s.prefix = buffer.New()
+ defer s.prefix.Free()
+ s.prefix.WriteString(s.h.groupPrefix)
+ s.openGroups()
+ r.Attrs(func(a Attr) bool {
+ s.appendAttr(a)
+ return true
+ })
+ if s.h.json {
+ // Close all open groups.
+ for range s.h.groups {
+ s.buf.WriteByte('}')
+ }
+ // Close the top-level object.
+ s.buf.WriteByte('}')
+ }
+}
+
+// attrSep returns the separator between attributes.
+func (h *commonHandler) attrSep() string {
+ if h.json {
+ return ","
+ }
+ return " "
+}
+
+// handleState holds state for a single call to commonHandler.handle.
+// The initial value of sep determines whether to emit a separator
+// before the next key, after which it stays true.
+type handleState struct {
+ h *commonHandler
+ buf *buffer.Buffer
+ freeBuf bool // should buf be freed?
+ sep string // separator to write before next key
+ prefix *buffer.Buffer // for text: key prefix
+ groups *[]string // pool-allocated slice of active groups, for ReplaceAttr
+}
+
+var groupPool = sync.Pool{New: func() any {
+ s := make([]string, 0, 10)
+ return &s
+}}
+
+func (h *commonHandler) newHandleState(buf *buffer.Buffer, freeBuf bool, sep string, prefix *buffer.Buffer) handleState {
+ s := handleState{
+ h: h,
+ buf: buf,
+ freeBuf: freeBuf,
+ sep: sep,
+ prefix: prefix,
+ }
+ if h.opts.ReplaceAttr != nil {
+ s.groups = groupPool.Get().(*[]string)
+ *s.groups = append(*s.groups, h.groups[:h.nOpenGroups]...)
+ }
+ return s
+}
+
+func (s *handleState) free() {
+ if s.freeBuf {
+ s.buf.Free()
+ }
+ if gs := s.groups; gs != nil {
+ *gs = (*gs)[:0]
+ groupPool.Put(gs)
+ }
+}
+
+func (s *handleState) openGroups() {
+ for _, n := range s.h.groups[s.h.nOpenGroups:] {
+ s.openGroup(n)
+ }
+}
+
+// Separator for group names and keys.
+const keyComponentSep = '.'
+
+// openGroup starts a new group of attributes
+// with the given name.
+func (s *handleState) openGroup(name string) {
+ if s.h.json {
+ s.appendKey(name)
+ s.buf.WriteByte('{')
+ s.sep = ""
+ } else {
+ s.prefix.WriteString(name)
+ s.prefix.WriteByte(keyComponentSep)
+ }
+ // Collect group names for ReplaceAttr.
+ if s.groups != nil {
+ *s.groups = append(*s.groups, name)
+ }
+}
+
+// closeGroup ends the group with the given name.
+func (s *handleState) closeGroup(name string) {
+ if s.h.json {
+ s.buf.WriteByte('}')
+ } else {
+ (*s.prefix) = (*s.prefix)[:len(*s.prefix)-len(name)-1 /* for keyComponentSep */]
+ }
+ s.sep = s.h.attrSep()
+ if s.groups != nil {
+ *s.groups = (*s.groups)[:len(*s.groups)-1]
+ }
+}
+
+// appendAttr appends the Attr's key and value using app.
+// It handles replacement and checking for an empty key.
+// after replacement).
+func (s *handleState) appendAttr(a Attr) {
+ if rep := s.h.opts.ReplaceAttr; rep != nil && a.Value.Kind() != KindGroup {
+ var gs []string
+ if s.groups != nil {
+ gs = *s.groups
+ }
+ // Resolve before calling ReplaceAttr, so the user doesn't have to.
+ a.Value = a.Value.Resolve()
+ a = rep(gs, a)
+ }
+ a.Value = a.Value.Resolve()
+ // Elide empty Attrs.
+ if a.isEmpty() {
+ return
+ }
+ // Special case: Source.
+ if v := a.Value; v.Kind() == KindAny {
+ if src, ok := v.Any().(*Source); ok {
+ if s.h.json {
+ a.Value = src.group()
+ } else {
+ a.Value = StringValue(fmt.Sprintf("%s:%d", src.File, src.Line))
+ }
+ }
+ }
+ if a.Value.Kind() == KindGroup {
+ attrs := a.Value.Group()
+ // Output only non-empty groups.
+ if len(attrs) > 0 {
+ // Inline a group with an empty key.
+ if a.Key != "" {
+ s.openGroup(a.Key)
+ }
+ for _, aa := range attrs {
+ s.appendAttr(aa)
+ }
+ if a.Key != "" {
+ s.closeGroup(a.Key)
+ }
+ }
+ } else {
+ s.appendKey(a.Key)
+ s.appendValue(a.Value)
+ }
+}
+
+func (s *handleState) appendError(err error) {
+ s.appendString(fmt.Sprintf("!ERROR:%v", err))
+}
+
+func (s *handleState) appendKey(key string) {
+ s.buf.WriteString(s.sep)
+ if s.prefix != nil {
+ // TODO: optimize by avoiding allocation.
+ s.appendString(string(*s.prefix) + key)
+ } else {
+ s.appendString(key)
+ }
+ if s.h.json {
+ s.buf.WriteByte(':')
+ } else {
+ s.buf.WriteByte('=')
+ }
+ s.sep = s.h.attrSep()
+}
+
+func (s *handleState) appendString(str string) {
+ if s.h.json {
+ s.buf.WriteByte('"')
+ *s.buf = appendEscapedJSONString(*s.buf, str)
+ s.buf.WriteByte('"')
+ } else {
+ // text
+ if needsQuoting(str) {
+ *s.buf = strconv.AppendQuote(*s.buf, str)
+ } else {
+ s.buf.WriteString(str)
+ }
+ }
+}
+
+func (s *handleState) appendValue(v Value) {
+ defer func() {
+ if r := recover(); r != nil {
+ // If it panics with a nil pointer, the most likely cases are
+ // an encoding.TextMarshaler or error fails to guard against nil,
+ // in which case "<nil>" seems to be the feasible choice.
+ //
+ // Adapted from the code in fmt/print.go.
+ if v := reflect.ValueOf(v.any); v.Kind() == reflect.Pointer && v.IsNil() {
+ s.appendString("<nil>")
+ return
+ }
+
+ // Otherwise just print the original panic message.
+ s.appendString(fmt.Sprintf("!PANIC: %v", r))
+ }
+ }()
+
+ var err error
+ if s.h.json {
+ err = appendJSONValue(s, v)
+ } else {
+ err = appendTextValue(s, v)
+ }
+ if err != nil {
+ s.appendError(err)
+ }
+}
+
+func (s *handleState) appendTime(t time.Time) {
+ if s.h.json {
+ appendJSONTime(s, t)
+ } else {
+ writeTimeRFC3339Millis(s.buf, t)
+ }
+}
+
+// This takes half the time of Time.AppendFormat.
+func writeTimeRFC3339Millis(buf *buffer.Buffer, t time.Time) {
+ year, month, day := t.Date()
+ buf.WritePosIntWidth(year, 4)
+ buf.WriteByte('-')
+ buf.WritePosIntWidth(int(month), 2)
+ buf.WriteByte('-')
+ buf.WritePosIntWidth(day, 2)
+ buf.WriteByte('T')
+ hour, min, sec := t.Clock()
+ buf.WritePosIntWidth(hour, 2)
+ buf.WriteByte(':')
+ buf.WritePosIntWidth(min, 2)
+ buf.WriteByte(':')
+ buf.WritePosIntWidth(sec, 2)
+ ns := t.Nanosecond()
+ buf.WriteByte('.')
+ buf.WritePosIntWidth(ns/1e6, 3)
+ _, offsetSeconds := t.Zone()
+ if offsetSeconds == 0 {
+ buf.WriteByte('Z')
+ } else {
+ offsetMinutes := offsetSeconds / 60
+ if offsetMinutes < 0 {
+ buf.WriteByte('-')
+ offsetMinutes = -offsetMinutes
+ } else {
+ buf.WriteByte('+')
+ }
+ buf.WritePosIntWidth(offsetMinutes/60, 2)
+ buf.WriteByte(':')
+ buf.WritePosIntWidth(offsetMinutes%60, 2)
+ }
+}
diff --git a/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go b/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go
new file mode 100644
index 000000000..7786c166e
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/internal/buffer/buffer.go
@@ -0,0 +1,84 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package buffer provides a pool-allocated byte buffer.
+package buffer
+
+import (
+ "sync"
+)
+
+// Buffer adapted from go/src/fmt/print.go
+type Buffer []byte
+
+// Having an initial size gives a dramatic speedup.
+var bufPool = sync.Pool{
+ New: func() any {
+ b := make([]byte, 0, 1024)
+ return (*Buffer)(&b)
+ },
+}
+
+func New() *Buffer {
+ return bufPool.Get().(*Buffer)
+}
+
+func (b *Buffer) Free() {
+ // To reduce peak allocation, return only smaller buffers to the pool.
+ const maxBufferSize = 16 << 10
+ if cap(*b) <= maxBufferSize {
+ *b = (*b)[:0]
+ bufPool.Put(b)
+ }
+}
+
+func (b *Buffer) Reset() {
+ *b = (*b)[:0]
+}
+
+func (b *Buffer) Write(p []byte) (int, error) {
+ *b = append(*b, p...)
+ return len(p), nil
+}
+
+func (b *Buffer) WriteString(s string) {
+ *b = append(*b, s...)
+}
+
+func (b *Buffer) WriteByte(c byte) {
+ *b = append(*b, c)
+}
+
+func (b *Buffer) WritePosInt(i int) {
+ b.WritePosIntWidth(i, 0)
+}
+
+// WritePosIntWidth writes non-negative integer i to the buffer, padded on the left
+// by zeroes to the given width. Use a width of 0 to omit padding.
+func (b *Buffer) WritePosIntWidth(i, width int) {
+ // Cheap integer to fixed-width decimal ASCII.
+ // Copied from log/log.go.
+
+ if i < 0 {
+ panic("negative int")
+ }
+
+ // Assemble decimal in reverse order.
+ var bb [20]byte
+ bp := len(bb) - 1
+ for i >= 10 || width > 1 {
+ width--
+ q := i / 10
+ bb[bp] = byte('0' + i - q*10)
+ bp--
+ i = q
+ }
+ // i < 10
+ bb[bp] = byte('0' + i)
+ b.Write(bb[bp:])
+}
+
+func (b *Buffer) String() string {
+ return string(*b)
+}
diff --git a/vendor/golang.org/x/exp/slog/internal/ignorepc.go b/vendor/golang.org/x/exp/slog/internal/ignorepc.go
new file mode 100644
index 000000000..d1256426f
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/internal/ignorepc.go
@@ -0,0 +1,9 @@
+// Copyright 2023 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package internal
+
+// If IgnorePC is true, do not invoke runtime.Callers to get the pc.
+// This is solely for benchmarking the slowdown from runtime.Callers.
+var IgnorePC = false
diff --git a/vendor/golang.org/x/exp/slog/json_handler.go b/vendor/golang.org/x/exp/slog/json_handler.go
new file mode 100644
index 000000000..157ada869
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/json_handler.go
@@ -0,0 +1,336 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "time"
+ "unicode/utf8"
+
+ "golang.org/x/exp/slog/internal/buffer"
+)
+
+// JSONHandler is a Handler that writes Records to an io.Writer as
+// line-delimited JSON objects.
+type JSONHandler struct {
+ *commonHandler
+}
+
+// NewJSONHandler creates a JSONHandler that writes to w,
+// using the given options.
+// If opts is nil, the default options are used.
+func NewJSONHandler(w io.Writer, opts *HandlerOptions) *JSONHandler {
+ if opts == nil {
+ opts = &HandlerOptions{}
+ }
+ return &JSONHandler{
+ &commonHandler{
+ json: true,
+ w: w,
+ opts: *opts,
+ },
+ }
+}
+
+// Enabled reports whether the handler handles records at the given level.
+// The handler ignores records whose level is lower.
+func (h *JSONHandler) Enabled(_ context.Context, level Level) bool {
+ return h.commonHandler.enabled(level)
+}
+
+// WithAttrs returns a new JSONHandler whose attributes consists
+// of h's attributes followed by attrs.
+func (h *JSONHandler) WithAttrs(attrs []Attr) Handler {
+ return &JSONHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
+}
+
+func (h *JSONHandler) WithGroup(name string) Handler {
+ return &JSONHandler{commonHandler: h.commonHandler.withGroup(name)}
+}
+
+// Handle formats its argument Record as a JSON object on a single line.
+//
+// If the Record's time is zero, the time is omitted.
+// Otherwise, the key is "time"
+// and the value is output as with json.Marshal.
+//
+// If the Record's level is zero, the level is omitted.
+// Otherwise, the key is "level"
+// and the value of [Level.String] is output.
+//
+// If the AddSource option is set and source information is available,
+// the key is "source"
+// and the value is output as "FILE:LINE".
+//
+// The message's key is "msg".
+//
+// To modify these or other attributes, or remove them from the output, use
+// [HandlerOptions.ReplaceAttr].
+//
+// Values are formatted as with an [encoding/json.Encoder] with SetEscapeHTML(false),
+// with two exceptions.
+//
+// First, an Attr whose Value is of type error is formatted as a string, by
+// calling its Error method. Only errors in Attrs receive this special treatment,
+// not errors embedded in structs, slices, maps or other data structures that
+// are processed by the encoding/json package.
+//
+// Second, an encoding failure does not cause Handle to return an error.
+// Instead, the error message is formatted as a string.
+//
+// Each call to Handle results in a single serialized call to io.Writer.Write.
+func (h *JSONHandler) Handle(_ context.Context, r Record) error {
+ return h.commonHandler.handle(r)
+}
+
+// Adapted from time.Time.MarshalJSON to avoid allocation.
+func appendJSONTime(s *handleState, t time.Time) {
+ if y := t.Year(); y < 0 || y >= 10000 {
+ // RFC 3339 is clear that years are 4 digits exactly.
+ // See golang.org/issue/4556#c15 for more discussion.
+ s.appendError(errors.New("time.Time year outside of range [0,9999]"))
+ }
+ s.buf.WriteByte('"')
+ *s.buf = t.AppendFormat(*s.buf, time.RFC3339Nano)
+ s.buf.WriteByte('"')
+}
+
+func appendJSONValue(s *handleState, v Value) error {
+ switch v.Kind() {
+ case KindString:
+ s.appendString(v.str())
+ case KindInt64:
+ *s.buf = strconv.AppendInt(*s.buf, v.Int64(), 10)
+ case KindUint64:
+ *s.buf = strconv.AppendUint(*s.buf, v.Uint64(), 10)
+ case KindFloat64:
+ // json.Marshal is funny about floats; it doesn't
+ // always match strconv.AppendFloat. So just call it.
+ // That's expensive, but floats are rare.
+ if err := appendJSONMarshal(s.buf, v.Float64()); err != nil {
+ return err
+ }
+ case KindBool:
+ *s.buf = strconv.AppendBool(*s.buf, v.Bool())
+ case KindDuration:
+ // Do what json.Marshal does.
+ *s.buf = strconv.AppendInt(*s.buf, int64(v.Duration()), 10)
+ case KindTime:
+ s.appendTime(v.Time())
+ case KindAny:
+ a := v.Any()
+ _, jm := a.(json.Marshaler)
+ if err, ok := a.(error); ok && !jm {
+ s.appendString(err.Error())
+ } else {
+ return appendJSONMarshal(s.buf, a)
+ }
+ default:
+ panic(fmt.Sprintf("bad kind: %s", v.Kind()))
+ }
+ return nil
+}
+
+func appendJSONMarshal(buf *buffer.Buffer, v any) error {
+ // Use a json.Encoder to avoid escaping HTML.
+ var bb bytes.Buffer
+ enc := json.NewEncoder(&bb)
+ enc.SetEscapeHTML(false)
+ if err := enc.Encode(v); err != nil {
+ return err
+ }
+ bs := bb.Bytes()
+ buf.Write(bs[:len(bs)-1]) // remove final newline
+ return nil
+}
+
+// appendEscapedJSONString escapes s for JSON and appends it to buf.
+// It does not surround the string in quotation marks.
+//
+// Modified from encoding/json/encode.go:encodeState.string,
+// with escapeHTML set to false.
+func appendEscapedJSONString(buf []byte, s string) []byte {
+ char := func(b byte) { buf = append(buf, b) }
+ str := func(s string) { buf = append(buf, s...) }
+
+ start := 0
+ for i := 0; i < len(s); {
+ if b := s[i]; b < utf8.RuneSelf {
+ if safeSet[b] {
+ i++
+ continue
+ }
+ if start < i {
+ str(s[start:i])
+ }
+ char('\\')
+ switch b {
+ case '\\', '"':
+ char(b)
+ case '\n':
+ char('n')
+ case '\r':
+ char('r')
+ case '\t':
+ char('t')
+ default:
+ // This encodes bytes < 0x20 except for \t, \n and \r.
+ str(`u00`)
+ char(hex[b>>4])
+ char(hex[b&0xF])
+ }
+ i++
+ start = i
+ continue
+ }
+ c, size := utf8.DecodeRuneInString(s[i:])
+ if c == utf8.RuneError && size == 1 {
+ if start < i {
+ str(s[start:i])
+ }
+ str(`\ufffd`)
+ i += size
+ start = i
+ continue
+ }
+ // U+2028 is LINE SEPARATOR.
+ // U+2029 is PARAGRAPH SEPARATOR.
+ // They are both technically valid characters in JSON strings,
+ // but don't work in JSONP, which has to be evaluated as JavaScript,
+ // and can lead to security holes there. It is valid JSON to
+ // escape them, so we do so unconditionally.
+ // See http://timelessrepo.com/json-isnt-a-javascript-subset for discussion.
+ if c == '\u2028' || c == '\u2029' {
+ if start < i {
+ str(s[start:i])
+ }
+ str(`\u202`)
+ char(hex[c&0xF])
+ i += size
+ start = i
+ continue
+ }
+ i += size
+ }
+ if start < len(s) {
+ str(s[start:])
+ }
+ return buf
+}
+
+var hex = "0123456789abcdef"
+
+// Copied from encoding/json/tables.go.
+//
+// safeSet holds the value true if the ASCII character with the given array
+// position can be represented inside a JSON string without any further
+// escaping.
+//
+// All values are true except for the ASCII control characters (0-31), the
+// double quote ("), and the backslash character ("\").
+var safeSet = [utf8.RuneSelf]bool{
+ ' ': true,
+ '!': true,
+ '"': false,
+ '#': true,
+ '$': true,
+ '%': true,
+ '&': true,
+ '\'': true,
+ '(': true,
+ ')': true,
+ '*': true,
+ '+': true,
+ ',': true,
+ '-': true,
+ '.': true,
+ '/': true,
+ '0': true,
+ '1': true,
+ '2': true,
+ '3': true,
+ '4': true,
+ '5': true,
+ '6': true,
+ '7': true,
+ '8': true,
+ '9': true,
+ ':': true,
+ ';': true,
+ '<': true,
+ '=': true,
+ '>': true,
+ '?': true,
+ '@': true,
+ 'A': true,
+ 'B': true,
+ 'C': true,
+ 'D': true,
+ 'E': true,
+ 'F': true,
+ 'G': true,
+ 'H': true,
+ 'I': true,
+ 'J': true,
+ 'K': true,
+ 'L': true,
+ 'M': true,
+ 'N': true,
+ 'O': true,
+ 'P': true,
+ 'Q': true,
+ 'R': true,
+ 'S': true,
+ 'T': true,
+ 'U': true,
+ 'V': true,
+ 'W': true,
+ 'X': true,
+ 'Y': true,
+ 'Z': true,
+ '[': true,
+ '\\': false,
+ ']': true,
+ '^': true,
+ '_': true,
+ '`': true,
+ 'a': true,
+ 'b': true,
+ 'c': true,
+ 'd': true,
+ 'e': true,
+ 'f': true,
+ 'g': true,
+ 'h': true,
+ 'i': true,
+ 'j': true,
+ 'k': true,
+ 'l': true,
+ 'm': true,
+ 'n': true,
+ 'o': true,
+ 'p': true,
+ 'q': true,
+ 'r': true,
+ 's': true,
+ 't': true,
+ 'u': true,
+ 'v': true,
+ 'w': true,
+ 'x': true,
+ 'y': true,
+ 'z': true,
+ '{': true,
+ '|': true,
+ '}': true,
+ '~': true,
+ '\u007f': true,
+}
diff --git a/vendor/golang.org/x/exp/slog/level.go b/vendor/golang.org/x/exp/slog/level.go
new file mode 100644
index 000000000..b2365f0aa
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/level.go
@@ -0,0 +1,201 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "sync/atomic"
+)
+
+// A Level is the importance or severity of a log event.
+// The higher the level, the more important or severe the event.
+type Level int
+
+// Level numbers are inherently arbitrary,
+// but we picked them to satisfy three constraints.
+// Any system can map them to another numbering scheme if it wishes.
+//
+// First, we wanted the default level to be Info, Since Levels are ints, Info is
+// the default value for int, zero.
+//
+
+// Second, we wanted to make it easy to use levels to specify logger verbosity.
+// Since a larger level means a more severe event, a logger that accepts events
+// with smaller (or more negative) level means a more verbose logger. Logger
+// verbosity is thus the negation of event severity, and the default verbosity
+// of 0 accepts all events at least as severe as INFO.
+//
+// Third, we wanted some room between levels to accommodate schemes with named
+// levels between ours. For example, Google Cloud Logging defines a Notice level
+// between Info and Warn. Since there are only a few of these intermediate
+// levels, the gap between the numbers need not be large. Our gap of 4 matches
+// OpenTelemetry's mapping. Subtracting 9 from an OpenTelemetry level in the
+// DEBUG, INFO, WARN and ERROR ranges converts it to the corresponding slog
+// Level range. OpenTelemetry also has the names TRACE and FATAL, which slog
+// does not. But those OpenTelemetry levels can still be represented as slog
+// Levels by using the appropriate integers.
+//
+// Names for common levels.
+const (
+ LevelDebug Level = -4
+ LevelInfo Level = 0
+ LevelWarn Level = 4
+ LevelError Level = 8
+)
+
+// String returns a name for the level.
+// If the level has a name, then that name
+// in uppercase is returned.
+// If the level is between named values, then
+// an integer is appended to the uppercased name.
+// Examples:
+//
+// LevelWarn.String() => "WARN"
+// (LevelInfo+2).String() => "INFO+2"
+func (l Level) String() string {
+ str := func(base string, val Level) string {
+ if val == 0 {
+ return base
+ }
+ return fmt.Sprintf("%s%+d", base, val)
+ }
+
+ switch {
+ case l < LevelInfo:
+ return str("DEBUG", l-LevelDebug)
+ case l < LevelWarn:
+ return str("INFO", l-LevelInfo)
+ case l < LevelError:
+ return str("WARN", l-LevelWarn)
+ default:
+ return str("ERROR", l-LevelError)
+ }
+}
+
+// MarshalJSON implements [encoding/json.Marshaler]
+// by quoting the output of [Level.String].
+func (l Level) MarshalJSON() ([]byte, error) {
+ // AppendQuote is sufficient for JSON-encoding all Level strings.
+ // They don't contain any runes that would produce invalid JSON
+ // when escaped.
+ return strconv.AppendQuote(nil, l.String()), nil
+}
+
+// UnmarshalJSON implements [encoding/json.Unmarshaler]
+// It accepts any string produced by [Level.MarshalJSON],
+// ignoring case.
+// It also accepts numeric offsets that would result in a different string on
+// output. For example, "Error-8" would marshal as "INFO".
+func (l *Level) UnmarshalJSON(data []byte) error {
+ s, err := strconv.Unquote(string(data))
+ if err != nil {
+ return err
+ }
+ return l.parse(s)
+}
+
+// MarshalText implements [encoding.TextMarshaler]
+// by calling [Level.String].
+func (l Level) MarshalText() ([]byte, error) {
+ return []byte(l.String()), nil
+}
+
+// UnmarshalText implements [encoding.TextUnmarshaler].
+// It accepts any string produced by [Level.MarshalText],
+// ignoring case.
+// It also accepts numeric offsets that would result in a different string on
+// output. For example, "Error-8" would marshal as "INFO".
+func (l *Level) UnmarshalText(data []byte) error {
+ return l.parse(string(data))
+}
+
+func (l *Level) parse(s string) (err error) {
+ defer func() {
+ if err != nil {
+ err = fmt.Errorf("slog: level string %q: %w", s, err)
+ }
+ }()
+
+ name := s
+ offset := 0
+ if i := strings.IndexAny(s, "+-"); i >= 0 {
+ name = s[:i]
+ offset, err = strconv.Atoi(s[i:])
+ if err != nil {
+ return err
+ }
+ }
+ switch strings.ToUpper(name) {
+ case "DEBUG":
+ *l = LevelDebug
+ case "INFO":
+ *l = LevelInfo
+ case "WARN":
+ *l = LevelWarn
+ case "ERROR":
+ *l = LevelError
+ default:
+ return errors.New("unknown name")
+ }
+ *l += Level(offset)
+ return nil
+}
+
+// Level returns the receiver.
+// It implements Leveler.
+func (l Level) Level() Level { return l }
+
+// A LevelVar is a Level variable, to allow a Handler level to change
+// dynamically.
+// It implements Leveler as well as a Set method,
+// and it is safe for use by multiple goroutines.
+// The zero LevelVar corresponds to LevelInfo.
+type LevelVar struct {
+ val atomic.Int64
+}
+
+// Level returns v's level.
+func (v *LevelVar) Level() Level {
+ return Level(int(v.val.Load()))
+}
+
+// Set sets v's level to l.
+func (v *LevelVar) Set(l Level) {
+ v.val.Store(int64(l))
+}
+
+func (v *LevelVar) String() string {
+ return fmt.Sprintf("LevelVar(%s)", v.Level())
+}
+
+// MarshalText implements [encoding.TextMarshaler]
+// by calling [Level.MarshalText].
+func (v *LevelVar) MarshalText() ([]byte, error) {
+ return v.Level().MarshalText()
+}
+
+// UnmarshalText implements [encoding.TextUnmarshaler]
+// by calling [Level.UnmarshalText].
+func (v *LevelVar) UnmarshalText(data []byte) error {
+ var l Level
+ if err := l.UnmarshalText(data); err != nil {
+ return err
+ }
+ v.Set(l)
+ return nil
+}
+
+// A Leveler provides a Level value.
+//
+// As Level itself implements Leveler, clients typically supply
+// a Level value wherever a Leveler is needed, such as in HandlerOptions.
+// Clients who need to vary the level dynamically can provide a more complex
+// Leveler implementation such as *LevelVar.
+type Leveler interface {
+ Level() Level
+}
diff --git a/vendor/golang.org/x/exp/slog/logger.go b/vendor/golang.org/x/exp/slog/logger.go
new file mode 100644
index 000000000..e87ec9936
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/logger.go
@@ -0,0 +1,343 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "context"
+ "log"
+ "runtime"
+ "sync/atomic"
+ "time"
+
+ "golang.org/x/exp/slog/internal"
+)
+
+var defaultLogger atomic.Value
+
+func init() {
+ defaultLogger.Store(New(newDefaultHandler(log.Output)))
+}
+
+// Default returns the default Logger.
+func Default() *Logger { return defaultLogger.Load().(*Logger) }
+
+// SetDefault makes l the default Logger.
+// After this call, output from the log package's default Logger
+// (as with [log.Print], etc.) will be logged at LevelInfo using l's Handler.
+func SetDefault(l *Logger) {
+ defaultLogger.Store(l)
+ // If the default's handler is a defaultHandler, then don't use a handleWriter,
+ // or we'll deadlock as they both try to acquire the log default mutex.
+ // The defaultHandler will use whatever the log default writer is currently
+ // set to, which is correct.
+ // This can occur with SetDefault(Default()).
+ // See TestSetDefault.
+ if _, ok := l.Handler().(*defaultHandler); !ok {
+ capturePC := log.Flags()&(log.Lshortfile|log.Llongfile) != 0
+ log.SetOutput(&handlerWriter{l.Handler(), LevelInfo, capturePC})
+ log.SetFlags(0) // we want just the log message, no time or location
+ }
+}
+
+// handlerWriter is an io.Writer that calls a Handler.
+// It is used to link the default log.Logger to the default slog.Logger.
+type handlerWriter struct {
+ h Handler
+ level Level
+ capturePC bool
+}
+
+func (w *handlerWriter) Write(buf []byte) (int, error) {
+ if !w.h.Enabled(context.Background(), w.level) {
+ return 0, nil
+ }
+ var pc uintptr
+ if !internal.IgnorePC && w.capturePC {
+ // skip [runtime.Callers, w.Write, Logger.Output, log.Print]
+ var pcs [1]uintptr
+ runtime.Callers(4, pcs[:])
+ pc = pcs[0]
+ }
+
+ // Remove final newline.
+ origLen := len(buf) // Report that the entire buf was written.
+ if len(buf) > 0 && buf[len(buf)-1] == '\n' {
+ buf = buf[:len(buf)-1]
+ }
+ r := NewRecord(time.Now(), w.level, string(buf), pc)
+ return origLen, w.h.Handle(context.Background(), r)
+}
+
+// A Logger records structured information about each call to its
+// Log, Debug, Info, Warn, and Error methods.
+// For each call, it creates a Record and passes it to a Handler.
+//
+// To create a new Logger, call [New] or a Logger method
+// that begins "With".
+type Logger struct {
+ handler Handler // for structured logging
+}
+
+func (l *Logger) clone() *Logger {
+ c := *l
+ return &c
+}
+
+// Handler returns l's Handler.
+func (l *Logger) Handler() Handler { return l.handler }
+
+// With returns a new Logger that includes the given arguments, converted to
+// Attrs as in [Logger.Log].
+// The Attrs will be added to each output from the Logger.
+// The new Logger shares the old Logger's context.
+// The new Logger's handler is the result of calling WithAttrs on the receiver's
+// handler.
+func (l *Logger) With(args ...any) *Logger {
+ c := l.clone()
+ c.handler = l.handler.WithAttrs(argsToAttrSlice(args))
+ return c
+}
+
+// WithGroup returns a new Logger that starts a group. The keys of all
+// attributes added to the Logger will be qualified by the given name.
+// (How that qualification happens depends on the [Handler.WithGroup]
+// method of the Logger's Handler.)
+// The new Logger shares the old Logger's context.
+//
+// The new Logger's handler is the result of calling WithGroup on the receiver's
+// handler.
+func (l *Logger) WithGroup(name string) *Logger {
+ c := l.clone()
+ c.handler = l.handler.WithGroup(name)
+ return c
+
+}
+
+// New creates a new Logger with the given non-nil Handler and a nil context.
+func New(h Handler) *Logger {
+ if h == nil {
+ panic("nil Handler")
+ }
+ return &Logger{handler: h}
+}
+
+// With calls Logger.With on the default logger.
+func With(args ...any) *Logger {
+ return Default().With(args...)
+}
+
+// Enabled reports whether l emits log records at the given context and level.
+func (l *Logger) Enabled(ctx context.Context, level Level) bool {
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ return l.Handler().Enabled(ctx, level)
+}
+
+// NewLogLogger returns a new log.Logger such that each call to its Output method
+// dispatches a Record to the specified handler. The logger acts as a bridge from
+// the older log API to newer structured logging handlers.
+func NewLogLogger(h Handler, level Level) *log.Logger {
+ return log.New(&handlerWriter{h, level, true}, "", 0)
+}
+
+// Log emits a log record with the current time and the given level and message.
+// The Record's Attrs consist of the Logger's attributes followed by
+// the Attrs specified by args.
+//
+// The attribute arguments are processed as follows:
+// - If an argument is an Attr, it is used as is.
+// - If an argument is a string and this is not the last argument,
+// the following argument is treated as the value and the two are combined
+// into an Attr.
+// - Otherwise, the argument is treated as a value with key "!BADKEY".
+func (l *Logger) Log(ctx context.Context, level Level, msg string, args ...any) {
+ l.log(ctx, level, msg, args...)
+}
+
+// LogAttrs is a more efficient version of [Logger.Log] that accepts only Attrs.
+func (l *Logger) LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
+ l.logAttrs(ctx, level, msg, attrs...)
+}
+
+// Debug logs at LevelDebug.
+func (l *Logger) Debug(msg string, args ...any) {
+ l.log(nil, LevelDebug, msg, args...)
+}
+
+// DebugContext logs at LevelDebug with the given context.
+func (l *Logger) DebugContext(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelDebug, msg, args...)
+}
+
+// DebugCtx logs at LevelDebug with the given context.
+// Deprecated: Use Logger.DebugContext.
+func (l *Logger) DebugCtx(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelDebug, msg, args...)
+}
+
+// Info logs at LevelInfo.
+func (l *Logger) Info(msg string, args ...any) {
+ l.log(nil, LevelInfo, msg, args...)
+}
+
+// InfoContext logs at LevelInfo with the given context.
+func (l *Logger) InfoContext(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelInfo, msg, args...)
+}
+
+// InfoCtx logs at LevelInfo with the given context.
+// Deprecated: Use Logger.InfoContext.
+func (l *Logger) InfoCtx(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelInfo, msg, args...)
+}
+
+// Warn logs at LevelWarn.
+func (l *Logger) Warn(msg string, args ...any) {
+ l.log(nil, LevelWarn, msg, args...)
+}
+
+// WarnContext logs at LevelWarn with the given context.
+func (l *Logger) WarnContext(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelWarn, msg, args...)
+}
+
+// WarnCtx logs at LevelWarn with the given context.
+// Deprecated: Use Logger.WarnContext.
+func (l *Logger) WarnCtx(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelWarn, msg, args...)
+}
+
+// Error logs at LevelError.
+func (l *Logger) Error(msg string, args ...any) {
+ l.log(nil, LevelError, msg, args...)
+}
+
+// ErrorContext logs at LevelError with the given context.
+func (l *Logger) ErrorContext(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelError, msg, args...)
+}
+
+// ErrorCtx logs at LevelError with the given context.
+// Deprecated: Use Logger.ErrorContext.
+func (l *Logger) ErrorCtx(ctx context.Context, msg string, args ...any) {
+ l.log(ctx, LevelError, msg, args...)
+}
+
+// log is the low-level logging method for methods that take ...any.
+// It must always be called directly by an exported logging method
+// or function, because it uses a fixed call depth to obtain the pc.
+func (l *Logger) log(ctx context.Context, level Level, msg string, args ...any) {
+ if !l.Enabled(ctx, level) {
+ return
+ }
+ var pc uintptr
+ if !internal.IgnorePC {
+ var pcs [1]uintptr
+ // skip [runtime.Callers, this function, this function's caller]
+ runtime.Callers(3, pcs[:])
+ pc = pcs[0]
+ }
+ r := NewRecord(time.Now(), level, msg, pc)
+ r.Add(args...)
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ _ = l.Handler().Handle(ctx, r)
+}
+
+// logAttrs is like [Logger.log], but for methods that take ...Attr.
+func (l *Logger) logAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
+ if !l.Enabled(ctx, level) {
+ return
+ }
+ var pc uintptr
+ if !internal.IgnorePC {
+ var pcs [1]uintptr
+ // skip [runtime.Callers, this function, this function's caller]
+ runtime.Callers(3, pcs[:])
+ pc = pcs[0]
+ }
+ r := NewRecord(time.Now(), level, msg, pc)
+ r.AddAttrs(attrs...)
+ if ctx == nil {
+ ctx = context.Background()
+ }
+ _ = l.Handler().Handle(ctx, r)
+}
+
+// Debug calls Logger.Debug on the default logger.
+func Debug(msg string, args ...any) {
+ Default().log(nil, LevelDebug, msg, args...)
+}
+
+// DebugContext calls Logger.DebugContext on the default logger.
+func DebugContext(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelDebug, msg, args...)
+}
+
+// Info calls Logger.Info on the default logger.
+func Info(msg string, args ...any) {
+ Default().log(nil, LevelInfo, msg, args...)
+}
+
+// InfoContext calls Logger.InfoContext on the default logger.
+func InfoContext(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelInfo, msg, args...)
+}
+
+// Warn calls Logger.Warn on the default logger.
+func Warn(msg string, args ...any) {
+ Default().log(nil, LevelWarn, msg, args...)
+}
+
+// WarnContext calls Logger.WarnContext on the default logger.
+func WarnContext(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelWarn, msg, args...)
+}
+
+// Error calls Logger.Error on the default logger.
+func Error(msg string, args ...any) {
+ Default().log(nil, LevelError, msg, args...)
+}
+
+// ErrorContext calls Logger.ErrorContext on the default logger.
+func ErrorContext(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelError, msg, args...)
+}
+
+// DebugCtx calls Logger.DebugContext on the default logger.
+// Deprecated: call DebugContext.
+func DebugCtx(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelDebug, msg, args...)
+}
+
+// InfoCtx calls Logger.InfoContext on the default logger.
+// Deprecated: call InfoContext.
+func InfoCtx(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelInfo, msg, args...)
+}
+
+// WarnCtx calls Logger.WarnContext on the default logger.
+// Deprecated: call WarnContext.
+func WarnCtx(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelWarn, msg, args...)
+}
+
+// ErrorCtx calls Logger.ErrorContext on the default logger.
+// Deprecated: call ErrorContext.
+func ErrorCtx(ctx context.Context, msg string, args ...any) {
+ Default().log(ctx, LevelError, msg, args...)
+}
+
+// Log calls Logger.Log on the default logger.
+func Log(ctx context.Context, level Level, msg string, args ...any) {
+ Default().log(ctx, level, msg, args...)
+}
+
+// LogAttrs calls Logger.LogAttrs on the default logger.
+func LogAttrs(ctx context.Context, level Level, msg string, attrs ...Attr) {
+ Default().logAttrs(ctx, level, msg, attrs...)
+}
diff --git a/vendor/golang.org/x/exp/slog/noplog.bench b/vendor/golang.org/x/exp/slog/noplog.bench
new file mode 100644
index 000000000..ed9296ff6
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/noplog.bench
@@ -0,0 +1,36 @@
+goos: linux
+goarch: amd64
+pkg: golang.org/x/exp/slog
+cpu: Intel(R) Xeon(R) CPU @ 2.20GHz
+BenchmarkNopLog/attrs-8 1000000 1090 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-8 1000000 1097 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-8 1000000 1078 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-8 1000000 1095 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-8 1000000 1096 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-parallel-8 4007268 308.2 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-parallel-8 4016138 299.7 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-parallel-8 4020529 305.9 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-parallel-8 3977829 303.4 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/attrs-parallel-8 3225438 318.5 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/keys-values-8 1179256 994.2 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/keys-values-8 1000000 1002 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/keys-values-8 1216710 993.2 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/keys-values-8 1000000 1013 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/keys-values-8 1000000 1016 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-8 989066 1163 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-8 994116 1163 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-8 1000000 1152 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-8 991675 1165 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-8 965268 1166 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-parallel-8 3955503 303.3 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-parallel-8 3861188 307.8 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-parallel-8 3967752 303.9 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-parallel-8 3955203 302.7 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/WithContext-parallel-8 3948278 301.1 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/Ctx-8 940622 1247 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/Ctx-8 936381 1257 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/Ctx-8 959730 1266 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/Ctx-8 943473 1290 ns/op 0 B/op 0 allocs/op
+BenchmarkNopLog/Ctx-8 919414 1259 ns/op 0 B/op 0 allocs/op
+PASS
+ok golang.org/x/exp/slog 40.566s
diff --git a/vendor/golang.org/x/exp/slog/record.go b/vendor/golang.org/x/exp/slog/record.go
new file mode 100644
index 000000000..38b3440f7
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/record.go
@@ -0,0 +1,207 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "runtime"
+ "time"
+
+ "golang.org/x/exp/slices"
+)
+
+const nAttrsInline = 5
+
+// A Record holds information about a log event.
+// Copies of a Record share state.
+// Do not modify a Record after handing out a copy to it.
+// Use [Record.Clone] to create a copy with no shared state.
+type Record struct {
+ // The time at which the output method (Log, Info, etc.) was called.
+ Time time.Time
+
+ // The log message.
+ Message string
+
+ // The level of the event.
+ Level Level
+
+ // The program counter at the time the record was constructed, as determined
+ // by runtime.Callers. If zero, no program counter is available.
+ //
+ // The only valid use for this value is as an argument to
+ // [runtime.CallersFrames]. In particular, it must not be passed to
+ // [runtime.FuncForPC].
+ PC uintptr
+
+ // Allocation optimization: an inline array sized to hold
+ // the majority of log calls (based on examination of open-source
+ // code). It holds the start of the list of Attrs.
+ front [nAttrsInline]Attr
+
+ // The number of Attrs in front.
+ nFront int
+
+ // The list of Attrs except for those in front.
+ // Invariants:
+ // - len(back) > 0 iff nFront == len(front)
+ // - Unused array elements are zero. Used to detect mistakes.
+ back []Attr
+}
+
+// NewRecord creates a Record from the given arguments.
+// Use [Record.AddAttrs] to add attributes to the Record.
+//
+// NewRecord is intended for logging APIs that want to support a [Handler] as
+// a backend.
+func NewRecord(t time.Time, level Level, msg string, pc uintptr) Record {
+ return Record{
+ Time: t,
+ Message: msg,
+ Level: level,
+ PC: pc,
+ }
+}
+
+// Clone returns a copy of the record with no shared state.
+// The original record and the clone can both be modified
+// without interfering with each other.
+func (r Record) Clone() Record {
+ r.back = slices.Clip(r.back) // prevent append from mutating shared array
+ return r
+}
+
+// NumAttrs returns the number of attributes in the Record.
+func (r Record) NumAttrs() int {
+ return r.nFront + len(r.back)
+}
+
+// Attrs calls f on each Attr in the Record.
+// Iteration stops if f returns false.
+func (r Record) Attrs(f func(Attr) bool) {
+ for i := 0; i < r.nFront; i++ {
+ if !f(r.front[i]) {
+ return
+ }
+ }
+ for _, a := range r.back {
+ if !f(a) {
+ return
+ }
+ }
+}
+
+// AddAttrs appends the given Attrs to the Record's list of Attrs.
+func (r *Record) AddAttrs(attrs ...Attr) {
+ n := copy(r.front[r.nFront:], attrs)
+ r.nFront += n
+ // Check if a copy was modified by slicing past the end
+ // and seeing if the Attr there is non-zero.
+ if cap(r.back) > len(r.back) {
+ end := r.back[:len(r.back)+1][len(r.back)]
+ if !end.isEmpty() {
+ panic("copies of a slog.Record were both modified")
+ }
+ }
+ r.back = append(r.back, attrs[n:]...)
+}
+
+// Add converts the args to Attrs as described in [Logger.Log],
+// then appends the Attrs to the Record's list of Attrs.
+func (r *Record) Add(args ...any) {
+ var a Attr
+ for len(args) > 0 {
+ a, args = argsToAttr(args)
+ if r.nFront < len(r.front) {
+ r.front[r.nFront] = a
+ r.nFront++
+ } else {
+ if r.back == nil {
+ r.back = make([]Attr, 0, countAttrs(args))
+ }
+ r.back = append(r.back, a)
+ }
+ }
+
+}
+
+// countAttrs returns the number of Attrs that would be created from args.
+func countAttrs(args []any) int {
+ n := 0
+ for i := 0; i < len(args); i++ {
+ n++
+ if _, ok := args[i].(string); ok {
+ i++
+ }
+ }
+ return n
+}
+
+const badKey = "!BADKEY"
+
+// argsToAttr turns a prefix of the nonempty args slice into an Attr
+// and returns the unconsumed portion of the slice.
+// If args[0] is an Attr, it returns it.
+// If args[0] is a string, it treats the first two elements as
+// a key-value pair.
+// Otherwise, it treats args[0] as a value with a missing key.
+func argsToAttr(args []any) (Attr, []any) {
+ switch x := args[0].(type) {
+ case string:
+ if len(args) == 1 {
+ return String(badKey, x), nil
+ }
+ return Any(x, args[1]), args[2:]
+
+ case Attr:
+ return x, args[1:]
+
+ default:
+ return Any(badKey, x), args[1:]
+ }
+}
+
+// Source describes the location of a line of source code.
+type Source struct {
+ // Function is the package path-qualified function name containing the
+ // source line. If non-empty, this string uniquely identifies a single
+ // function in the program. This may be the empty string if not known.
+ Function string `json:"function"`
+ // File and Line are the file name and line number (1-based) of the source
+ // line. These may be the empty string and zero, respectively, if not known.
+ File string `json:"file"`
+ Line int `json:"line"`
+}
+
+// attrs returns the non-zero fields of s as a slice of attrs.
+// It is similar to a LogValue method, but we don't want Source
+// to implement LogValuer because it would be resolved before
+// the ReplaceAttr function was called.
+func (s *Source) group() Value {
+ var as []Attr
+ if s.Function != "" {
+ as = append(as, String("function", s.Function))
+ }
+ if s.File != "" {
+ as = append(as, String("file", s.File))
+ }
+ if s.Line != 0 {
+ as = append(as, Int("line", s.Line))
+ }
+ return GroupValue(as...)
+}
+
+// source returns a Source for the log event.
+// If the Record was created without the necessary information,
+// or if the location is unavailable, it returns a non-nil *Source
+// with zero fields.
+func (r Record) source() *Source {
+ fs := runtime.CallersFrames([]uintptr{r.PC})
+ f, _ := fs.Next()
+ return &Source{
+ Function: f.Function,
+ File: f.File,
+ Line: f.Line,
+ }
+}
diff --git a/vendor/golang.org/x/exp/slog/text_handler.go b/vendor/golang.org/x/exp/slog/text_handler.go
new file mode 100644
index 000000000..75b66b716
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/text_handler.go
@@ -0,0 +1,161 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "context"
+ "encoding"
+ "fmt"
+ "io"
+ "reflect"
+ "strconv"
+ "unicode"
+ "unicode/utf8"
+)
+
+// TextHandler is a Handler that writes Records to an io.Writer as a
+// sequence of key=value pairs separated by spaces and followed by a newline.
+type TextHandler struct {
+ *commonHandler
+}
+
+// NewTextHandler creates a TextHandler that writes to w,
+// using the given options.
+// If opts is nil, the default options are used.
+func NewTextHandler(w io.Writer, opts *HandlerOptions) *TextHandler {
+ if opts == nil {
+ opts = &HandlerOptions{}
+ }
+ return &TextHandler{
+ &commonHandler{
+ json: false,
+ w: w,
+ opts: *opts,
+ },
+ }
+}
+
+// Enabled reports whether the handler handles records at the given level.
+// The handler ignores records whose level is lower.
+func (h *TextHandler) Enabled(_ context.Context, level Level) bool {
+ return h.commonHandler.enabled(level)
+}
+
+// WithAttrs returns a new TextHandler whose attributes consists
+// of h's attributes followed by attrs.
+func (h *TextHandler) WithAttrs(attrs []Attr) Handler {
+ return &TextHandler{commonHandler: h.commonHandler.withAttrs(attrs)}
+}
+
+func (h *TextHandler) WithGroup(name string) Handler {
+ return &TextHandler{commonHandler: h.commonHandler.withGroup(name)}
+}
+
+// Handle formats its argument Record as a single line of space-separated
+// key=value items.
+//
+// If the Record's time is zero, the time is omitted.
+// Otherwise, the key is "time"
+// and the value is output in RFC3339 format with millisecond precision.
+//
+// If the Record's level is zero, the level is omitted.
+// Otherwise, the key is "level"
+// and the value of [Level.String] is output.
+//
+// If the AddSource option is set and source information is available,
+// the key is "source" and the value is output as FILE:LINE.
+//
+// The message's key is "msg".
+//
+// To modify these or other attributes, or remove them from the output, use
+// [HandlerOptions.ReplaceAttr].
+//
+// If a value implements [encoding.TextMarshaler], the result of MarshalText is
+// written. Otherwise, the result of fmt.Sprint is written.
+//
+// Keys and values are quoted with [strconv.Quote] if they contain Unicode space
+// characters, non-printing characters, '"' or '='.
+//
+// Keys inside groups consist of components (keys or group names) separated by
+// dots. No further escaping is performed.
+// Thus there is no way to determine from the key "a.b.c" whether there
+// are two groups "a" and "b" and a key "c", or a single group "a.b" and a key "c",
+// or single group "a" and a key "b.c".
+// If it is necessary to reconstruct the group structure of a key
+// even in the presence of dots inside components, use
+// [HandlerOptions.ReplaceAttr] to encode that information in the key.
+//
+// Each call to Handle results in a single serialized call to
+// io.Writer.Write.
+func (h *TextHandler) Handle(_ context.Context, r Record) error {
+ return h.commonHandler.handle(r)
+}
+
+func appendTextValue(s *handleState, v Value) error {
+ switch v.Kind() {
+ case KindString:
+ s.appendString(v.str())
+ case KindTime:
+ s.appendTime(v.time())
+ case KindAny:
+ if tm, ok := v.any.(encoding.TextMarshaler); ok {
+ data, err := tm.MarshalText()
+ if err != nil {
+ return err
+ }
+ // TODO: avoid the conversion to string.
+ s.appendString(string(data))
+ return nil
+ }
+ if bs, ok := byteSlice(v.any); ok {
+ // As of Go 1.19, this only allocates for strings longer than 32 bytes.
+ s.buf.WriteString(strconv.Quote(string(bs)))
+ return nil
+ }
+ s.appendString(fmt.Sprintf("%+v", v.Any()))
+ default:
+ *s.buf = v.append(*s.buf)
+ }
+ return nil
+}
+
+// byteSlice returns its argument as a []byte if the argument's
+// underlying type is []byte, along with a second return value of true.
+// Otherwise it returns nil, false.
+func byteSlice(a any) ([]byte, bool) {
+ if bs, ok := a.([]byte); ok {
+ return bs, true
+ }
+ // Like Printf's %s, we allow both the slice type and the byte element type to be named.
+ t := reflect.TypeOf(a)
+ if t != nil && t.Kind() == reflect.Slice && t.Elem().Kind() == reflect.Uint8 {
+ return reflect.ValueOf(a).Bytes(), true
+ }
+ return nil, false
+}
+
+func needsQuoting(s string) bool {
+ if len(s) == 0 {
+ return true
+ }
+ for i := 0; i < len(s); {
+ b := s[i]
+ if b < utf8.RuneSelf {
+ // Quote anything except a backslash that would need quoting in a
+ // JSON string, as well as space and '='
+ if b != '\\' && (b == ' ' || b == '=' || !safeSet[b]) {
+ return true
+ }
+ i++
+ continue
+ }
+ r, size := utf8.DecodeRuneInString(s[i:])
+ if r == utf8.RuneError || unicode.IsSpace(r) || !unicode.IsPrint(r) {
+ return true
+ }
+ i += size
+ }
+ return false
+}
diff --git a/vendor/golang.org/x/exp/slog/value.go b/vendor/golang.org/x/exp/slog/value.go
new file mode 100644
index 000000000..3550c46fc
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/value.go
@@ -0,0 +1,456 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package slog
+
+import (
+ "fmt"
+ "math"
+ "runtime"
+ "strconv"
+ "strings"
+ "time"
+ "unsafe"
+
+ "golang.org/x/exp/slices"
+)
+
+// A Value can represent any Go value, but unlike type any,
+// it can represent most small values without an allocation.
+// The zero Value corresponds to nil.
+type Value struct {
+ _ [0]func() // disallow ==
+ // num holds the value for Kinds Int64, Uint64, Float64, Bool and Duration,
+ // the string length for KindString, and nanoseconds since the epoch for KindTime.
+ num uint64
+ // If any is of type Kind, then the value is in num as described above.
+ // If any is of type *time.Location, then the Kind is Time and time.Time value
+ // can be constructed from the Unix nanos in num and the location (monotonic time
+ // is not preserved).
+ // If any is of type stringptr, then the Kind is String and the string value
+ // consists of the length in num and the pointer in any.
+ // Otherwise, the Kind is Any and any is the value.
+ // (This implies that Attrs cannot store values of type Kind, *time.Location
+ // or stringptr.)
+ any any
+}
+
+// Kind is the kind of a Value.
+type Kind int
+
+// The following list is sorted alphabetically, but it's also important that
+// KindAny is 0 so that a zero Value represents nil.
+
+const (
+ KindAny Kind = iota
+ KindBool
+ KindDuration
+ KindFloat64
+ KindInt64
+ KindString
+ KindTime
+ KindUint64
+ KindGroup
+ KindLogValuer
+)
+
+var kindStrings = []string{
+ "Any",
+ "Bool",
+ "Duration",
+ "Float64",
+ "Int64",
+ "String",
+ "Time",
+ "Uint64",
+ "Group",
+ "LogValuer",
+}
+
+func (k Kind) String() string {
+ if k >= 0 && int(k) < len(kindStrings) {
+ return kindStrings[k]
+ }
+ return "<unknown slog.Kind>"
+}
+
+// Unexported version of Kind, just so we can store Kinds in Values.
+// (No user-provided value has this type.)
+type kind Kind
+
+// Kind returns v's Kind.
+func (v Value) Kind() Kind {
+ switch x := v.any.(type) {
+ case Kind:
+ return x
+ case stringptr:
+ return KindString
+ case timeLocation:
+ return KindTime
+ case groupptr:
+ return KindGroup
+ case LogValuer:
+ return KindLogValuer
+ case kind: // a kind is just a wrapper for a Kind
+ return KindAny
+ default:
+ return KindAny
+ }
+}
+
+//////////////// Constructors
+
+// IntValue returns a Value for an int.
+func IntValue(v int) Value {
+ return Int64Value(int64(v))
+}
+
+// Int64Value returns a Value for an int64.
+func Int64Value(v int64) Value {
+ return Value{num: uint64(v), any: KindInt64}
+}
+
+// Uint64Value returns a Value for a uint64.
+func Uint64Value(v uint64) Value {
+ return Value{num: v, any: KindUint64}
+}
+
+// Float64Value returns a Value for a floating-point number.
+func Float64Value(v float64) Value {
+ return Value{num: math.Float64bits(v), any: KindFloat64}
+}
+
+// BoolValue returns a Value for a bool.
+func BoolValue(v bool) Value {
+ u := uint64(0)
+ if v {
+ u = 1
+ }
+ return Value{num: u, any: KindBool}
+}
+
+// Unexported version of *time.Location, just so we can store *time.Locations in
+// Values. (No user-provided value has this type.)
+type timeLocation *time.Location
+
+// TimeValue returns a Value for a time.Time.
+// It discards the monotonic portion.
+func TimeValue(v time.Time) Value {
+ if v.IsZero() {
+ // UnixNano on the zero time is undefined, so represent the zero time
+ // with a nil *time.Location instead. time.Time.Location method never
+ // returns nil, so a Value with any == timeLocation(nil) cannot be
+ // mistaken for any other Value, time.Time or otherwise.
+ return Value{any: timeLocation(nil)}
+ }
+ return Value{num: uint64(v.UnixNano()), any: timeLocation(v.Location())}
+}
+
+// DurationValue returns a Value for a time.Duration.
+func DurationValue(v time.Duration) Value {
+ return Value{num: uint64(v.Nanoseconds()), any: KindDuration}
+}
+
+// AnyValue returns a Value for the supplied value.
+//
+// If the supplied value is of type Value, it is returned
+// unmodified.
+//
+// Given a value of one of Go's predeclared string, bool, or
+// (non-complex) numeric types, AnyValue returns a Value of kind
+// String, Bool, Uint64, Int64, or Float64. The width of the
+// original numeric type is not preserved.
+//
+// Given a time.Time or time.Duration value, AnyValue returns a Value of kind
+// KindTime or KindDuration. The monotonic time is not preserved.
+//
+// For nil, or values of all other types, including named types whose
+// underlying type is numeric, AnyValue returns a value of kind KindAny.
+func AnyValue(v any) Value {
+ switch v := v.(type) {
+ case string:
+ return StringValue(v)
+ case int:
+ return Int64Value(int64(v))
+ case uint:
+ return Uint64Value(uint64(v))
+ case int64:
+ return Int64Value(v)
+ case uint64:
+ return Uint64Value(v)
+ case bool:
+ return BoolValue(v)
+ case time.Duration:
+ return DurationValue(v)
+ case time.Time:
+ return TimeValue(v)
+ case uint8:
+ return Uint64Value(uint64(v))
+ case uint16:
+ return Uint64Value(uint64(v))
+ case uint32:
+ return Uint64Value(uint64(v))
+ case uintptr:
+ return Uint64Value(uint64(v))
+ case int8:
+ return Int64Value(int64(v))
+ case int16:
+ return Int64Value(int64(v))
+ case int32:
+ return Int64Value(int64(v))
+ case float64:
+ return Float64Value(v)
+ case float32:
+ return Float64Value(float64(v))
+ case []Attr:
+ return GroupValue(v...)
+ case Kind:
+ return Value{any: kind(v)}
+ case Value:
+ return v
+ default:
+ return Value{any: v}
+ }
+}
+
+//////////////// Accessors
+
+// Any returns v's value as an any.
+func (v Value) Any() any {
+ switch v.Kind() {
+ case KindAny:
+ if k, ok := v.any.(kind); ok {
+ return Kind(k)
+ }
+ return v.any
+ case KindLogValuer:
+ return v.any
+ case KindGroup:
+ return v.group()
+ case KindInt64:
+ return int64(v.num)
+ case KindUint64:
+ return v.num
+ case KindFloat64:
+ return v.float()
+ case KindString:
+ return v.str()
+ case KindBool:
+ return v.bool()
+ case KindDuration:
+ return v.duration()
+ case KindTime:
+ return v.time()
+ default:
+ panic(fmt.Sprintf("bad kind: %s", v.Kind()))
+ }
+}
+
+// Int64 returns v's value as an int64. It panics
+// if v is not a signed integer.
+func (v Value) Int64() int64 {
+ if g, w := v.Kind(), KindInt64; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+ return int64(v.num)
+}
+
+// Uint64 returns v's value as a uint64. It panics
+// if v is not an unsigned integer.
+func (v Value) Uint64() uint64 {
+ if g, w := v.Kind(), KindUint64; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+ return v.num
+}
+
+// Bool returns v's value as a bool. It panics
+// if v is not a bool.
+func (v Value) Bool() bool {
+ if g, w := v.Kind(), KindBool; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+ return v.bool()
+}
+
+func (v Value) bool() bool {
+ return v.num == 1
+}
+
+// Duration returns v's value as a time.Duration. It panics
+// if v is not a time.Duration.
+func (v Value) Duration() time.Duration {
+ if g, w := v.Kind(), KindDuration; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+
+ return v.duration()
+}
+
+func (v Value) duration() time.Duration {
+ return time.Duration(int64(v.num))
+}
+
+// Float64 returns v's value as a float64. It panics
+// if v is not a float64.
+func (v Value) Float64() float64 {
+ if g, w := v.Kind(), KindFloat64; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+
+ return v.float()
+}
+
+func (v Value) float() float64 {
+ return math.Float64frombits(v.num)
+}
+
+// Time returns v's value as a time.Time. It panics
+// if v is not a time.Time.
+func (v Value) Time() time.Time {
+ if g, w := v.Kind(), KindTime; g != w {
+ panic(fmt.Sprintf("Value kind is %s, not %s", g, w))
+ }
+ return v.time()
+}
+
+func (v Value) time() time.Time {
+ loc := v.any.(timeLocation)
+ if loc == nil {
+ return time.Time{}
+ }
+ return time.Unix(0, int64(v.num)).In(loc)
+}
+
+// LogValuer returns v's value as a LogValuer. It panics
+// if v is not a LogValuer.
+func (v Value) LogValuer() LogValuer {
+ return v.any.(LogValuer)
+}
+
+// Group returns v's value as a []Attr.
+// It panics if v's Kind is not KindGroup.
+func (v Value) Group() []Attr {
+ if sp, ok := v.any.(groupptr); ok {
+ return unsafe.Slice((*Attr)(sp), v.num)
+ }
+ panic("Group: bad kind")
+}
+
+func (v Value) group() []Attr {
+ return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
+}
+
+//////////////// Other
+
+// Equal reports whether v and w represent the same Go value.
+func (v Value) Equal(w Value) bool {
+ k1 := v.Kind()
+ k2 := w.Kind()
+ if k1 != k2 {
+ return false
+ }
+ switch k1 {
+ case KindInt64, KindUint64, KindBool, KindDuration:
+ return v.num == w.num
+ case KindString:
+ return v.str() == w.str()
+ case KindFloat64:
+ return v.float() == w.float()
+ case KindTime:
+ return v.time().Equal(w.time())
+ case KindAny, KindLogValuer:
+ return v.any == w.any // may panic if non-comparable
+ case KindGroup:
+ return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
+ default:
+ panic(fmt.Sprintf("bad kind: %s", k1))
+ }
+}
+
+// append appends a text representation of v to dst.
+// v is formatted as with fmt.Sprint.
+func (v Value) append(dst []byte) []byte {
+ switch v.Kind() {
+ case KindString:
+ return append(dst, v.str()...)
+ case KindInt64:
+ return strconv.AppendInt(dst, int64(v.num), 10)
+ case KindUint64:
+ return strconv.AppendUint(dst, v.num, 10)
+ case KindFloat64:
+ return strconv.AppendFloat(dst, v.float(), 'g', -1, 64)
+ case KindBool:
+ return strconv.AppendBool(dst, v.bool())
+ case KindDuration:
+ return append(dst, v.duration().String()...)
+ case KindTime:
+ return append(dst, v.time().String()...)
+ case KindGroup:
+ return fmt.Append(dst, v.group())
+ case KindAny, KindLogValuer:
+ return fmt.Append(dst, v.any)
+ default:
+ panic(fmt.Sprintf("bad kind: %s", v.Kind()))
+ }
+}
+
+// A LogValuer is any Go value that can convert itself into a Value for logging.
+//
+// This mechanism may be used to defer expensive operations until they are
+// needed, or to expand a single value into a sequence of components.
+type LogValuer interface {
+ LogValue() Value
+}
+
+const maxLogValues = 100
+
+// Resolve repeatedly calls LogValue on v while it implements LogValuer,
+// and returns the result.
+// If v resolves to a group, the group's attributes' values are not recursively
+// resolved.
+// If the number of LogValue calls exceeds a threshold, a Value containing an
+// error is returned.
+// Resolve's return value is guaranteed not to be of Kind KindLogValuer.
+func (v Value) Resolve() (rv Value) {
+ orig := v
+ defer func() {
+ if r := recover(); r != nil {
+ rv = AnyValue(fmt.Errorf("LogValue panicked\n%s", stack(3, 5)))
+ }
+ }()
+
+ for i := 0; i < maxLogValues; i++ {
+ if v.Kind() != KindLogValuer {
+ return v
+ }
+ v = v.LogValuer().LogValue()
+ }
+ err := fmt.Errorf("LogValue called too many times on Value of type %T", orig.Any())
+ return AnyValue(err)
+}
+
+func stack(skip, nFrames int) string {
+ pcs := make([]uintptr, nFrames+1)
+ n := runtime.Callers(skip+1, pcs)
+ if n == 0 {
+ return "(no stack)"
+ }
+ frames := runtime.CallersFrames(pcs[:n])
+ var b strings.Builder
+ i := 0
+ for {
+ frame, more := frames.Next()
+ fmt.Fprintf(&b, "called from %s (%s:%d)\n", frame.Function, frame.File, frame.Line)
+ if !more {
+ break
+ }
+ i++
+ if i >= nFrames {
+ fmt.Fprintf(&b, "(rest of stack elided)\n")
+ break
+ }
+ }
+ return b.String()
+}
diff --git a/vendor/golang.org/x/exp/slog/value_119.go b/vendor/golang.org/x/exp/slog/value_119.go
new file mode 100644
index 000000000..29b0d7329
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/value_119.go
@@ -0,0 +1,53 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.19 && !go1.20
+
+package slog
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+type (
+ stringptr unsafe.Pointer // used in Value.any when the Value is a string
+ groupptr unsafe.Pointer // used in Value.any when the Value is a []Attr
+)
+
+// StringValue returns a new Value for a string.
+func StringValue(value string) Value {
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&value))
+ return Value{num: uint64(hdr.Len), any: stringptr(hdr.Data)}
+}
+
+func (v Value) str() string {
+ var s string
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ hdr.Data = uintptr(v.any.(stringptr))
+ hdr.Len = int(v.num)
+ return s
+}
+
+// String returns Value's value as a string, formatted like fmt.Sprint. Unlike
+// the methods Int64, Float64, and so on, which panic if v is of the
+// wrong kind, String never panics.
+func (v Value) String() string {
+ if sp, ok := v.any.(stringptr); ok {
+ // Inlining this code makes a huge difference.
+ var s string
+ hdr := (*reflect.StringHeader)(unsafe.Pointer(&s))
+ hdr.Data = uintptr(sp)
+ hdr.Len = int(v.num)
+ return s
+ }
+ return string(v.append(nil))
+}
+
+// GroupValue returns a new Value for a list of Attrs.
+// The caller must not subsequently mutate the argument slice.
+func GroupValue(as ...Attr) Value {
+ hdr := (*reflect.SliceHeader)(unsafe.Pointer(&as))
+ return Value{num: uint64(hdr.Len), any: groupptr(hdr.Data)}
+}
diff --git a/vendor/golang.org/x/exp/slog/value_120.go b/vendor/golang.org/x/exp/slog/value_120.go
new file mode 100644
index 000000000..f7d4c0932
--- /dev/null
+++ b/vendor/golang.org/x/exp/slog/value_120.go
@@ -0,0 +1,39 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build go1.20
+
+package slog
+
+import "unsafe"
+
+type (
+ stringptr *byte // used in Value.any when the Value is a string
+ groupptr *Attr // used in Value.any when the Value is a []Attr
+)
+
+// StringValue returns a new Value for a string.
+func StringValue(value string) Value {
+ return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))}
+}
+
+// GroupValue returns a new Value for a list of Attrs.
+// The caller must not subsequently mutate the argument slice.
+func GroupValue(as ...Attr) Value {
+ return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
+}
+
+// String returns Value's value as a string, formatted like fmt.Sprint. Unlike
+// the methods Int64, Float64, and so on, which panic if v is of the
+// wrong kind, String never panics.
+func (v Value) String() string {
+ if sp, ok := v.any.(stringptr); ok {
+ return unsafe.String(sp, v.num)
+ }
+ return string(v.append(nil))
+}
+
+func (v Value) str() string {
+ return unsafe.String(v.any.(stringptr), v.num)
+}