mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2024-11-30 08:46:54 +02:00
47ac0d4df8
* Add empty value for KeyValue * Update CHANGELOG * Apply suggestions from code review Co-authored-by: Robert Pająk <pellared@hotmail.com> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> * Fix comments * Update log/keyvalue.go Co-authored-by: Damien Mathieu <42@dmathieu.com> --------- Co-authored-by: Robert Pająk <pellared@hotmail.com> Co-authored-by: Tyler Yahn <MrAlias@users.noreply.github.com> Co-authored-by: Damien Mathieu <42@dmathieu.com>
361 lines
10 KiB
Go
361 lines
10 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
// 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 log_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/go-logr/logr"
|
|
"github.com/go-logr/logr/testr"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"go.opentelemetry.io/otel/internal/global"
|
|
"go.opentelemetry.io/otel/log"
|
|
)
|
|
|
|
func TestKind(t *testing.T) {
|
|
testCases := []struct {
|
|
kind log.Kind
|
|
str string
|
|
value int
|
|
}{
|
|
{log.KindBool, "Bool", 1},
|
|
{log.KindBytes, "Bytes", 5},
|
|
{log.KindEmpty, "Empty", 0},
|
|
{log.KindFloat64, "Float64", 2},
|
|
{log.KindInt64, "Int64", 3},
|
|
{log.KindSlice, "Slice", 6},
|
|
{log.KindMap, "Map", 7},
|
|
{log.KindString, "String", 4},
|
|
}
|
|
for _, tc := range testCases {
|
|
t.Run(tc.str, func(t *testing.T) {
|
|
assert.Equal(t, tc.value, int(tc.kind), "Kind value")
|
|
assert.Equal(t, tc.str, tc.kind.String(), "Kind string")
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestValueEqual(t *testing.T) {
|
|
vals := []log.Value{
|
|
{},
|
|
log.Int64Value(1),
|
|
log.Int64Value(2),
|
|
log.Float64Value(3.5),
|
|
log.Float64Value(3.7),
|
|
log.BoolValue(true),
|
|
log.BoolValue(false),
|
|
log.StringValue("hi"),
|
|
log.StringValue("bye"),
|
|
log.BytesValue([]byte{1, 3, 5}),
|
|
log.SliceValue(log.StringValue("foo")),
|
|
log.SliceValue(log.IntValue(3), log.StringValue("foo")),
|
|
log.MapValue(log.Bool("b", true), log.Int("i", 3)),
|
|
log.MapValue(
|
|
log.Slice("l", log.IntValue(3), log.StringValue("foo")),
|
|
log.Bytes("b", []byte{3, 5, 7}),
|
|
log.Empty("e"),
|
|
),
|
|
}
|
|
for i, v1 := range vals {
|
|
for j, v2 := range vals {
|
|
assert.Equal(t, i == j, v1.Equal(v2), "%v.Equal(%v)", v1, v2)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestValueEmpty(t *testing.T) {
|
|
v := log.Value{}
|
|
t.Run("Value.Empty", func(t *testing.T) {
|
|
assert.True(t, v.Empty())
|
|
})
|
|
|
|
t.Run("Bytes", func(t *testing.T) {
|
|
assert.Nil(t, log.Bytes("b", nil).Value.AsBytes())
|
|
})
|
|
t.Run("Slice", func(t *testing.T) {
|
|
assert.Nil(t, log.Slice("s").Value.AsSlice())
|
|
})
|
|
t.Run("Map", func(t *testing.T) {
|
|
assert.Nil(t, log.Map("m").Value.AsMap())
|
|
})
|
|
}
|
|
|
|
func TestEmptyGroupsPreserved(t *testing.T) {
|
|
t.Run("Map", func(t *testing.T) {
|
|
assert.Equal(t, []log.KeyValue{
|
|
log.Int("a", 1),
|
|
log.Map("g1", log.Map("g2")),
|
|
log.Map("g3", log.Map("g4", log.Int("b", 2))),
|
|
}, log.MapValue(
|
|
log.Int("a", 1),
|
|
log.Map("g1", log.Map("g2")),
|
|
log.Map("g3", log.Map("g4", log.Int("b", 2))),
|
|
).AsMap())
|
|
})
|
|
|
|
t.Run("Slice", func(t *testing.T) {
|
|
assert.Equal(t, []log.Value{{}}, log.SliceValue(log.Value{}).AsSlice())
|
|
})
|
|
}
|
|
|
|
func TestBool(t *testing.T) {
|
|
const key, val = "key", true
|
|
kv := log.Bool(key, val)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindBool
|
|
t.Run("AsBool", func(t *testing.T) {
|
|
assert.Equal(t, val, kv.Value.AsBool(), "AsBool")
|
|
})
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestFloat64(t *testing.T) {
|
|
const key, val = "key", 3.0
|
|
kv := log.Float64(key, val)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindFloat64
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", func(t *testing.T) {
|
|
assert.Equal(t, val, v.AsFloat64(), "AsFloat64")
|
|
})
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestInt(t *testing.T) {
|
|
const key, val = "key", 1
|
|
kv := log.Int(key, val)
|
|
testKV[int64](t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindInt64
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", func(t *testing.T) {
|
|
assert.Equal(t, int64(val), v.AsInt64(), "AsInt64")
|
|
})
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestInt64(t *testing.T) {
|
|
const key, val = "key", 1
|
|
kv := log.Int64(key, val)
|
|
testKV[int64](t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindInt64
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", func(t *testing.T) {
|
|
assert.Equal(t, int64(val), v.AsInt64(), "AsInt64")
|
|
})
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestString(t *testing.T) {
|
|
const key, val = "key", "test string value"
|
|
kv := log.String(key, val)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindString
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", func(t *testing.T) {
|
|
assert.Equal(t, val, v.AsString(), "AsString")
|
|
})
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestBytes(t *testing.T) {
|
|
const key = "key"
|
|
val := []byte{3, 2, 1}
|
|
kv := log.Bytes(key, val)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindBytes
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", func(t *testing.T) {
|
|
assert.Equal(t, val, v.AsBytes(), "AsBytes")
|
|
})
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestSlice(t *testing.T) {
|
|
const key = "key"
|
|
val := []log.Value{log.IntValue(3), log.StringValue("foo")}
|
|
kv := log.Slice(key, val...)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindSlice
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", func(t *testing.T) {
|
|
assert.Equal(t, val, v.AsSlice(), "AsSlice")
|
|
})
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
func TestMap(t *testing.T) {
|
|
const key = "key"
|
|
val := []log.KeyValue{
|
|
log.Slice("l", log.IntValue(3), log.StringValue("foo")),
|
|
log.Bytes("b", []byte{3, 5, 7}),
|
|
}
|
|
kv := log.Map(key, val...)
|
|
testKV(t, key, val, kv)
|
|
|
|
v, k := kv.Value, log.KindMap
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", func(t *testing.T) {
|
|
assert.Equal(t, val, v.AsMap(), "AsMap")
|
|
})
|
|
}
|
|
|
|
func TestEmpty(t *testing.T) {
|
|
const key = "key"
|
|
kv := log.Empty(key)
|
|
|
|
assert.Equal(t, key, kv.Key, "incorrect key")
|
|
assert.True(t, kv.Value.Empty(), "value not empty")
|
|
|
|
v, k := kv.Value, log.KindEmpty
|
|
t.Run("AsBool", testErrKind(v.AsBool, "AsBool", k))
|
|
t.Run("AsFloat64", testErrKind(v.AsFloat64, "AsFloat64", k))
|
|
t.Run("AsInt64", testErrKind(v.AsInt64, "AsInt64", k))
|
|
t.Run("AsString", testErrKind(v.AsString, "AsString", k))
|
|
t.Run("AsBytes", testErrKind(v.AsBytes, "AsBytes", k))
|
|
t.Run("AsSlice", testErrKind(v.AsSlice, "AsSlice", k))
|
|
t.Run("AsMap", testErrKind(v.AsMap, "AsMap", k))
|
|
}
|
|
|
|
type logSink struct {
|
|
logr.LogSink
|
|
|
|
err error
|
|
msg string
|
|
keysAndValues []interface{}
|
|
}
|
|
|
|
func (l *logSink) Error(err error, msg string, keysAndValues ...interface{}) {
|
|
l.err, l.msg, l.keysAndValues = err, msg, keysAndValues
|
|
l.LogSink.Error(err, msg, keysAndValues)
|
|
}
|
|
|
|
func testErrKind[T any](f func() T, msg string, k log.Kind) func(*testing.T) {
|
|
return func(t *testing.T) {
|
|
t.Cleanup(func(l logr.Logger) func() {
|
|
return func() { global.SetLogger(l) }
|
|
}(global.GetLogger()))
|
|
|
|
l := &logSink{LogSink: testr.New(t).GetSink()}
|
|
global.SetLogger(logr.New(l))
|
|
|
|
assert.Zero(t, f())
|
|
|
|
assert.ErrorContains(t, l.err, "invalid Kind")
|
|
assert.Equal(t, msg, l.msg)
|
|
require.Len(t, l.keysAndValues, 2, "logged attributes")
|
|
assert.Equal(t, l.keysAndValues[1], k)
|
|
}
|
|
}
|
|
|
|
func testKV[T any](t *testing.T, key string, val T, kv log.KeyValue) {
|
|
t.Helper()
|
|
|
|
assert.Equal(t, key, kv.Key, "incorrect key")
|
|
assert.False(t, kv.Value.Empty(), "value empty")
|
|
}
|
|
|
|
func TestAllocationLimits(t *testing.T) {
|
|
const (
|
|
runs = 5
|
|
key = "key"
|
|
)
|
|
|
|
// Assign testing results to external scope so the compiler doesn't
|
|
// optimize away the testing statements.
|
|
var (
|
|
i int64
|
|
f float64
|
|
b bool
|
|
by []byte
|
|
s string
|
|
slice []log.Value
|
|
m []log.KeyValue
|
|
)
|
|
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
b = log.Bool(key, true).Value.AsBool()
|
|
}), "Bool.AsBool")
|
|
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
f = log.Float64(key, 3.0).Value.AsFloat64()
|
|
}), "Float.AsFloat64")
|
|
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
i = log.Int(key, 9).Value.AsInt64()
|
|
}), "Int.AsInt64")
|
|
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
i = log.Int64(key, 8).Value.AsInt64()
|
|
}), "Int64.AsInt64")
|
|
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
s = log.String(key, "value").Value.AsString()
|
|
}), "String.AsString")
|
|
|
|
byteVal := []byte{1, 3, 4}
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
by = log.Bytes(key, byteVal).Value.AsBytes()
|
|
}), "Byte.AsBytes")
|
|
|
|
sliceVal := []log.Value{log.BoolValue(true), log.IntValue(32)}
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
slice = log.Slice(key, sliceVal...).Value.AsSlice()
|
|
}), "Slice.AsSlice")
|
|
|
|
mapVal := []log.KeyValue{log.Bool("b", true), log.Int("i", 32)}
|
|
assert.Equal(t, 0.0, testing.AllocsPerRun(runs, func() {
|
|
m = log.Map(key, mapVal...).Value.AsMap()
|
|
}), "Map.AsMap")
|
|
|
|
// Convince the linter these values are used.
|
|
_, _, _, _, _, _, _ = i, f, b, by, s, slice, m
|
|
}
|