Skip to content

Commit

Permalink
Simplify Field API using generics (#44)
Browse files Browse the repository at this point in the history
Co-authored-by: Doug Lauder <[email protected]>
  • Loading branch information
hanzei and wiggin77 authored Nov 14, 2023
1 parent bcc267c commit a02d145
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 46 deletions.
40 changes: 20 additions & 20 deletions field.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,19 +269,19 @@ func fieldForAny(key string, val interface{}) Field {
}
return Bool(key, *v)
case float64:
return Float64(key, v)
return Float(key, v)
case *float64:
if v == nil {
return nilField(key)
}
return Float64(key, *v)
return Float(key, *v)
case float32:
return Float32(key, v)
return Float(key, v)
case *float32:
if v == nil {
return nilField(key)
}
return Float32(key, *v)
return Float(key, *v)
case int:
return Int(key, v)
case *int:
Expand All @@ -290,33 +290,33 @@ func fieldForAny(key string, val interface{}) Field {
}
return Int(key, *v)
case int64:
return Int64(key, v)
return Int(key, v)
case *int64:
if v == nil {
return nilField(key)
}
return Int64(key, *v)
return Int(key, *v)
case int32:
return Int32(key, v)
return Int(key, v)
case *int32:
if v == nil {
return nilField(key)
}
return Int32(key, *v)
return Int(key, *v)
case int16:
return Int32(key, int32(v))
return Int(key, int32(v))
case *int16:
if v == nil {
return nilField(key)
}
return Int32(key, int32(*v))
return Int(key, int32(*v))
case int8:
return Int32(key, int32(v))
return Int(key, int32(v))
case *int8:
if v == nil {
return nilField(key)
}
return Int32(key, int32(*v))
return Int(key, int32(*v))
case string:
return String(key, v)
case *string:
Expand All @@ -332,33 +332,33 @@ func fieldForAny(key string, val interface{}) Field {
}
return Uint(key, *v)
case uint64:
return Uint64(key, v)
return Uint(key, v)
case *uint64:
if v == nil {
return nilField(key)
}
return Uint64(key, *v)
return Uint(key, *v)
case uint32:
return Uint32(key, v)
return Uint(key, v)
case *uint32:
if v == nil {
return nilField(key)
}
return Uint32(key, *v)
return Uint(key, *v)
case uint16:
return Uint32(key, uint32(v))
return Uint(key, uint32(v))
case *uint16:
if v == nil {
return nilField(key)
}
return Uint32(key, uint32(*v))
return Uint(key, uint32(*v))
case uint8:
return Uint32(key, uint32(v))
return Uint(key, uint32(v))
case *uint8:
if v == nil {
return nilField(key)
}
return Uint32(key, uint32(*v))
return Uint(key, uint32(*v))
case []byte:
if v == nil {
return nilField(key)
Expand Down
33 changes: 25 additions & 8 deletions fieldapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,53 +9,70 @@ import (
// For best performance when passing a struct (or struct pointer),
// implement `logr.LogWriter` on the struct, otherwise reflection
// will be used to generate a string representation.
func Any(key string, val interface{}) Field {
func Any(key string, val any) Field {
return fieldForAny(key, val)
}

// Int64 constructs a field containing a key and Int64 value.
//
// Deprecated: Use [logr.Int] instead.
func Int64(key string, val int64) Field {
return Field{Key: key, Type: Int64Type, Integer: val}
}

// Int32 constructs a field containing a key and Int32 value.
//
// Deprecated: Use [logr.Int] instead.
func Int32(key string, val int32) Field {
return Field{Key: key, Type: Int32Type, Integer: int64(val)}
}

// Int constructs a field containing a key and Int value.
func Int(key string, val int) Field {
// Int constructs a field containing a key and int value.
func Int[T ~int | ~int8 | ~int16 | ~int32 | ~int64](key string, val T) Field {
return Field{Key: key, Type: IntType, Integer: int64(val)}
}

// Uint64 constructs a field containing a key and Uint64 value.
//
// Deprecated: Use [logr.Uint] instead.
func Uint64(key string, val uint64) Field {
return Field{Key: key, Type: Uint64Type, Integer: int64(val)}
}

// Uint32 constructs a field containing a key and Uint32 value.
//
// Deprecated: Use [logr.Uint] instead
func Uint32(key string, val uint32) Field {
return Field{Key: key, Type: Uint32Type, Integer: int64(val)}
}

// Uint constructs a field containing a key and Uint value.
func Uint(key string, val uint) Field {
// Uint constructs a field containing a key and uint value.
func Uint[T ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr](key string, val T) Field {
return Field{Key: key, Type: UintType, Integer: int64(val)}
}

// Float64 constructs a field containing a key and Float64 value.
//
// Deprecated: Use [logr.Float] instead
func Float64(key string, val float64) Field {
return Field{Key: key, Type: Float64Type, Float: val}
}

// Float32 constructs a field containing a key and Float32 value.
//
// Deprecated: Use [logr.Float] instead
func Float32(key string, val float32) Field {
return Field{Key: key, Type: Float32Type, Float: float64(val)}
}

// Float32 constructs a field containing a key and float value.
func Float[T ~float32 | ~float64](key string, val T) Field {
return Field{Key: key, Type: Float32Type, Float: float64(val)}
}

// String constructs a field containing a key and String value.
func String(key string, val string) Field {
return Field{Key: key, Type: StringType, String: val}
func String[T ~string](key string, val T) Field {
return Field{Key: key, Type: StringType, String: string(val)}
}

// Stringer constructs a field containing a key and a `fmt.Stringer` value.
Expand All @@ -75,7 +92,7 @@ func NamedErr(key string, err error) Field {
}

// Bool constructs a field containing a key and bool value.
func Bool(key string, val bool) Field {
func Bool[T ~bool](key string, val T) Field {
var b int64
if val {
b = 1
Expand Down
118 changes: 109 additions & 9 deletions fieldapi_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,125 @@
package logr

import "testing"
import (
"errors"
"testing"
"time"
)

func TestFieldInt(t *testing.T) {
_ = Int("int", int(0))
type myInt int
_ = Int("int", myInt(0))

_ = Int("int8", int8(0))
type myInt8 int8
_ = Int("int8", myInt8(0))

_ = Int("int16", int16(0))
type myInt16 int16
_ = Int("int16", myInt16(0))

_ = Int("int32", int32(0))
type myInt32 int32
_ = Int("int32", myInt32(0))

_ = Int("int64", int64(0))
type myInt64 int64
_ = Int("int64", myInt64(0))
}

func TestFieldUint(t *testing.T) {
_ = Uint("uint", uint(0))
type myUint uint
_ = Uint("uint", myUint(0))

_ = Uint("uint8", uint8(0))
type myUint8 uint8
_ = Uint("uint8", myUint8(0))

_ = Uint("uint16", uint16(0))
type myUint16 uint16
_ = Uint("uint16", myUint16(0))

_ = Uint("uint32", uint32(0))
type myUint32 uint32
_ = Uint("uint32", myUint32(0))

_ = Uint("uint64", uint64(0))
type myUint64 uint64
_ = Uint("uint64", myUint64(0))

_ = Uint("uintptr", uintptr(0))
type myUintptr uintptr
_ = Uint("uintptr", myUintptr(0))
}

func TestFieldFloat(t *testing.T) {
_ = Float("float32", float32(0))
type myFloat32 float32
_ = Float("float32", myFloat32(0))

_ = Float("float64", float64(0))
type myFloat64 float32
_ = Float("float64", myFloat64(0))
}

func TestFieldString(t *testing.T) {
_ = String("string", "foo")
type myString string
_ = String("string", myString("foo"))
}

func TestFieldStringer(t *testing.T) {
_ = Stringer("stringer", time.Now())
type myStringer = time.Time
_ = Stringer("stringer", myStringer(time.Now()))
}

func TestFieldErr(t *testing.T) {
_ = Err(errors.New("some error"))
type myError error
_ = Err(myError(errors.New("some error")))
}

func TestFieldNamedErr(t *testing.T) {
_ = NamedErr("named err", errors.New("some error"))
type myError error
_ = NamedErr("named err", myError(errors.New("some error")))
}

func TestFieldBool(t *testing.T) {
_ = Bool("bool", false)
type myBool bool
_ = Bool("bool", myBool(false))
}

func TestFieldDuration(t *testing.T) {
_ = Duration("duration", time.Duration(0))
}

func TestFieldMillis(t *testing.T) {
_ = Millis("millis", int64(0))
}

func TestFieldArray(t *testing.T) {
Array("array", []string{})
Array("array", []any{})
_ = Array("array", []string{})
_ = Array("array", []any{})

type myArray []any
Array("array", myArray{})
_ = Array("array", myArray{})

type myGenericArray[T any] []T
Array("array", myGenericArray[any]{})
_ = Array("array", myGenericArray[any]{})
}

func TestFieldMap(t *testing.T) {
Map("array", map[string]any{})
Map("array", map[int]any{})
_ = Map("array", map[string]any{})
_ = Map("array", map[int]any{})

type myMap map[string]string
Map("array", myMap{})
_ = Map("array", myMap{})

type myGenericMap[K comparable, V any] map[K]V
Map("array", myGenericMap[int, any]{})
_ = Map("array", myGenericMap[int, any]{})
}
2 changes: 1 addition & 1 deletion formatters/json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestJSONFieldTypes(t *testing.T) {
logr.String("f1", "one"),
logr.Int("f2", 77),
logr.Bool("f3", true),
logr.Float64("f4", 3.14),
logr.Float("f4", 3.14),
logr.Err(errors.New("test error")),
)
err = lgr.Flush()
Expand Down
6 changes: 3 additions & 3 deletions test/cmd/metrics/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,9 @@ func main() {
logged2, filtered2 := test.DoSomeLogging(cfg)

lgr.NewLogger().Log(lvl, "Logr test completed.",
logr.Uint32("errors", atomic.LoadUint32(&errorCount)),
logr.Uint32("queueFull", atomic.LoadUint32(&queueFullCount)),
logr.Uint32("targetFull", atomic.LoadUint32(&targetQueueFullCount)),
logr.Uint("errors", atomic.LoadUint32(&errorCount)),
logr.Uint("queueFull", atomic.LoadUint32(&queueFullCount)),
logr.Uint("targetFull", atomic.LoadUint32(&targetQueueFullCount)),
)

close(done)
Expand Down
6 changes: 3 additions & 3 deletions test/cmd/testapp1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,9 @@ func main() {
logged2, filtered2 := test.DoSomeLogging(cfg)

lgr.NewLogger().Log(lvl, "Logr test completed.",
logr.Uint32("errors", atomic.LoadUint32(&errorCount)),
logr.Uint32("queueFull", atomic.LoadUint32(&queueFullCount)),
logr.Uint32("targetFull", atomic.LoadUint32(&targetQueueFullCount)),
logr.Uint("errors", atomic.LoadUint32(&errorCount)),
logr.Uint("queueFull", atomic.LoadUint32(&queueFullCount)),
logr.Uint("targetFull", atomic.LoadUint32(&targetQueueFullCount)),
)

close(done)
Expand Down
4 changes: 2 additions & 2 deletions test/load.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func DoSomeLogging(cfg DoSomeLoggingCfg) (logged int32, filtered int32) {
defer wg.Done()
tid := atomic.AddInt32(&id, 1)
logger := cfg.Lgr.NewLogger().With(
logr.Int32("id", tid),
logr.Int("id", tid),
logr.Int("rnd", rand.Intn(100)),
)

Expand All @@ -52,7 +52,7 @@ func DoSomeLogging(cfg DoSomeLoggingCfg) (logged int32, filtered int32) {
}
lc := atomic.AddInt32(&logCount, 1)
logger.Log(cfg.Lvl, "This is some sample text.",
logr.Int32("count", lc),
logr.Int("count", lc),
logr.String("good", cfg.GoodToken),
)

Expand Down

0 comments on commit a02d145

Please sign in to comment.