- Remove the norace_test.go files, moving their contents elsewhere.
- Rename the internal/testutil package to internal/slogtest.
- Remove value_unsafe.go, moving its contents to value.go.
Updates golang/go#56345.
Change-Id: I2a24ace5aea47f7a3067cd671f606c4fb279d744
Reviewed-on: https://go-review.googlesource.com/c/go/+/478197
Run-TryBot: Jonathan Amsterdam <jba@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Ian Lance Taylor <iant@google.com>
log/slog/internal, log/slog/internal/buffer,
slices
< log/slog
- < log/slog/internal/testutil;
+ < log/slog/internal/slogtest;
NET, log
< net/mail;
import (
"context"
"log/slog"
- "log/slog/internal/testutil"
+ "log/slog/internal/slogtest"
"os"
)
// Another typical use would be to decrease the log level (to LevelDebug, say)
// during a part of the program that was suspected of containing a bug.
func ExampleHandler_levelHandler() {
- th := slog.HandlerOptions{ReplaceAttr: testutil.RemoveTime}.NewTextHandler(os.Stdout)
+ th := slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime}.NewTextHandler(os.Stdout)
logger := slog.New(NewLevelHandler(slog.LevelWarn, th))
logger.Info("not printed")
logger.Warn("printed")
import (
"log/slog"
- "log/slog/internal/testutil"
+ "log/slog/internal/slogtest"
"os"
)
// with an alternative representation to avoid revealing secrets.
func ExampleLogValuer_secret() {
t := Token("shhhh!")
- logger := slog.New(slog.HandlerOptions{ReplaceAttr: testutil.RemoveTime}.
+ logger := slog.New(slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime}.
NewTextHandler(os.Stdout))
logger.Info("permission granted", "user", "Perry", "token", t)
import (
"log/slog"
- "log/slog/internal/testutil"
+ "log/slog/internal/slogtest"
"net/http"
"os"
"time"
r, _ := http.NewRequest("GET", "localhost", nil)
// ...
- logger := slog.New(slog.HandlerOptions{ReplaceAttr: testutil.RemoveTime}.NewTextHandler(os.Stdout))
+ logger := slog.New(slog.HandlerOptions{ReplaceAttr: slogtest.RemoveTime}.NewTextHandler(os.Stdout))
slog.SetDefault(logger)
slog.Info("finished",
package buffer
-import "testing"
+import (
+ "internal/race"
+ "internal/testenv"
+ "testing"
+)
func Test(t *testing.T) {
b := New()
t.Errorf("got %q, want %q", got, want)
}
}
+
+func TestAlloc(t *testing.T) {
+ if race.Enabled {
+ t.Skip("skipping test in race mode")
+ }
+ testenv.SkipIfOptimizationOff(t)
+ got := int(testing.AllocsPerRun(5, func() {
+ b := New()
+ defer b.Free()
+ b.WriteString("not 1K worth of bytes")
+ }))
+ if got != 0 {
+ t.Errorf("got %d allocs, want 0", got)
+ }
+}
+++ /dev/null
-// 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
-
-import (
- "internal/race"
- "internal/testenv"
- "testing"
-)
-
-func TestAlloc(t *testing.T) {
- if race.Enabled {
- t.Skip("skipping test in race mode")
- }
- testenv.SkipIfOptimizationOff(t)
- got := int(testing.AllocsPerRun(5, func() {
- b := New()
- defer b.Free()
- b.WriteString("not 1K worth of bytes")
- }))
- if got != 0 {
- t.Errorf("got %d allocs, want 0", got)
- }
-}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package testutil contains support functions for testing.
-package testutil
+// Package slogtest contains support functions for testing slog.
+package slogtest
import "log/slog"
import (
"bytes"
"context"
+ "internal/race"
+ "internal/testenv"
"io"
"log"
"path/filepath"
runtime.Callers(depth, pcs[:])
return pcs[0]
}
+
+func wantAllocs(t *testing.T, want int, f func()) {
+ if race.Enabled {
+ t.Skip("skipping test in race mode")
+ }
+ testenv.SkipIfOptimizationOff(t)
+ t.Helper()
+ got := int(testing.AllocsPerRun(5, f))
+ if got != want {
+ t.Errorf("got %d allocs, want %d", got, want)
+ }
+}
+++ /dev/null
-// 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 (
- "internal/race"
- "internal/testenv"
- "testing"
-)
-
-func wantAllocs(t *testing.T, want int, f func()) {
- if race.Enabled {
- t.Skip("skipping test in race mode")
- }
- testenv.SkipIfOptimizationOff(t)
- t.Helper()
- got := int(testing.AllocsPerRun(5, f))
- if got != want {
- t.Errorf("got %d allocs, want %d", got, want)
- }
-}
"slices"
"strconv"
"time"
+ "unsafe"
)
-// Definitions for Value.
-// The Value type itself can be found in value_{safe,unsafe}.go.
+// 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 {
+ // 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
+}
+
+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
+)
// Kind is the kind of a Value.
type Kind int
// (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
+// StringValue returns a new Value for a string.
+func StringValue(value string) Value {
+ return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))}
+}
+
// IntValue returns a Value for an int.
func IntValue(v int) Value {
return Int64Value(int64(v))
// 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 groupValue(as)
+ return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
}
// AnyValue returns a Value for the supplied value.
case KindLogValuer:
return v.any
case KindGroup:
- return v.uncheckedGroup()
+ return v.group()
case KindInt64:
return int64(v.num)
case KindUint64:
}
}
+// 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)
+ }
+ var buf []byte
+ return string(v.append(buf))
+}
+
+func (v Value) str() string {
+ return unsafe.String(v.any.(stringptr), v.num)
+}
+
// Int64 returns v's value as an int64. It panics
// if v is not a signed integer.
func (v Value) Int64() int64 {
// Group returns v's value as a []Attr.
// It panics if v's Kind is not KindGroup.
func (v Value) Group() []Attr {
- return v.group()
+ 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
case KindAny, KindLogValuer:
return v.any == w.any // may panic if non-comparable
case KindGroup:
- return slices.EqualFunc(v.uncheckedGroup(), w.uncheckedGroup(), Attr.Equal)
+ return slices.EqualFunc(v.group(), w.group(), Attr.Equal)
default:
panic(fmt.Sprintf("bad kind: %s", k1))
}
+++ /dev/null
-// 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 (
- "unsafe"
-)
-
-// 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 {
- // 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
-}
-
-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
-)
-
-// 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
- }
-}
-
-// StringValue returns a new Value for a string.
-func StringValue(value string) Value {
- return Value{num: uint64(len(value)), any: stringptr(unsafe.StringData(value))}
-}
-
-func (v Value) str() string {
- return unsafe.String(v.any.(stringptr), v.num)
-}
-
-// 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)
- }
- var buf []byte
- return string(v.append(buf))
-}
-
-func groupValue(as []Attr) Value {
- return Value{num: uint64(len(as)), any: groupptr(unsafe.SliceData(as))}
-}
-
-// group returns the Value's value as a []Attr.
-// It panics if the Value'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) uncheckedGroup() []Attr {
- return unsafe.Slice((*Attr)(v.any.(groupptr)), v.num)
-}