1// Copyright (c) 2016 Uber Technologies, Inc. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a copy 4// of this software and associated documentation files (the "Software"), to deal 5// in the Software without restriction, including without limitation the rights 6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7// copies of the Software, and to permit persons to whom the Software is 8// furnished to do so, subject to the following conditions: 9// 10// The above copyright notice and this permission notice shall be included in 11// all copies or substantial portions of the Software. 12// 13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19// THE SOFTWARE. 20 21package zap 22 23import ( 24 "net" 25 "sync" 26 "testing" 27 "time" 28 29 "github.com/stretchr/testify/assert" 30 "go.uber.org/zap/zapcore" 31) 32 33type username string 34 35func (n username) MarshalLogObject(enc zapcore.ObjectEncoder) error { 36 enc.AddString("username", string(n)) 37 return nil 38} 39 40func assertCanBeReused(t testing.TB, field Field) { 41 var wg sync.WaitGroup 42 43 for i := 0; i < 100; i++ { 44 enc := zapcore.NewMapObjectEncoder() 45 46 // Ensure using the field in multiple encoders in separate goroutines 47 // does not cause any races or panics. 48 wg.Add(1) 49 go func() { 50 defer wg.Done() 51 assert.NotPanics(t, func() { 52 field.AddTo(enc) 53 }, "Reusing a field should not cause issues") 54 }() 55 } 56 57 wg.Wait() 58} 59 60func TestFieldConstructors(t *testing.T) { 61 // Interface types. 62 addr := net.ParseIP("1.2.3.4") 63 name := username("phil") 64 ints := []int{5, 6} 65 66 tests := []struct { 67 name string 68 field Field 69 expect Field 70 }{ 71 {"Skip", Field{Type: zapcore.SkipType}, Skip()}, 72 {"Binary", Field{Key: "k", Type: zapcore.BinaryType, Interface: []byte("ab12")}, Binary("k", []byte("ab12"))}, 73 {"Bool", Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)}, 74 {"Bool", Field{Key: "k", Type: zapcore.BoolType, Integer: 1}, Bool("k", true)}, 75 {"ByteString", Field{Key: "k", Type: zapcore.ByteStringType, Interface: []byte("ab12")}, ByteString("k", []byte("ab12"))}, 76 {"Complex128", Field{Key: "k", Type: zapcore.Complex128Type, Interface: 1 + 2i}, Complex128("k", 1+2i)}, 77 {"Complex64", Field{Key: "k", Type: zapcore.Complex64Type, Interface: complex64(1 + 2i)}, Complex64("k", 1+2i)}, 78 {"Duration", Field{Key: "k", Type: zapcore.DurationType, Integer: 1}, Duration("k", 1)}, 79 {"Int", Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int("k", 1)}, 80 {"Int64", Field{Key: "k", Type: zapcore.Int64Type, Integer: 1}, Int64("k", 1)}, 81 {"Int32", Field{Key: "k", Type: zapcore.Int32Type, Integer: 1}, Int32("k", 1)}, 82 {"Int16", Field{Key: "k", Type: zapcore.Int16Type, Integer: 1}, Int16("k", 1)}, 83 {"Int8", Field{Key: "k", Type: zapcore.Int8Type, Integer: 1}, Int8("k", 1)}, 84 {"String", Field{Key: "k", Type: zapcore.StringType, String: "foo"}, String("k", "foo")}, 85 {"Time", Field{Key: "k", Type: zapcore.TimeType, Integer: 0, Interface: time.UTC}, Time("k", time.Unix(0, 0).In(time.UTC))}, 86 {"Time", Field{Key: "k", Type: zapcore.TimeType, Integer: 1000, Interface: time.UTC}, Time("k", time.Unix(0, 1000).In(time.UTC))}, 87 {"Uint", Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint("k", 1)}, 88 {"Uint64", Field{Key: "k", Type: zapcore.Uint64Type, Integer: 1}, Uint64("k", 1)}, 89 {"Uint32", Field{Key: "k", Type: zapcore.Uint32Type, Integer: 1}, Uint32("k", 1)}, 90 {"Uint16", Field{Key: "k", Type: zapcore.Uint16Type, Integer: 1}, Uint16("k", 1)}, 91 {"Uint8", Field{Key: "k", Type: zapcore.Uint8Type, Integer: 1}, Uint8("k", 1)}, 92 {"Uintptr", Field{Key: "k", Type: zapcore.UintptrType, Integer: 10}, Uintptr("k", 0xa)}, 93 {"Reflect", Field{Key: "k", Type: zapcore.ReflectType, Interface: ints}, Reflect("k", ints)}, 94 {"Stringer", Field{Key: "k", Type: zapcore.StringerType, Interface: addr}, Stringer("k", addr)}, 95 {"Object", Field{Key: "k", Type: zapcore.ObjectMarshalerType, Interface: name}, Object("k", name)}, 96 {"Any:ObjectMarshaler", Any("k", name), Object("k", name)}, 97 {"Any:ArrayMarshaler", Any("k", bools([]bool{true})), Array("k", bools([]bool{true}))}, 98 {"Any:Stringer", Any("k", addr), Stringer("k", addr)}, 99 {"Any:Bool", Any("k", true), Bool("k", true)}, 100 {"Any:Bools", Any("k", []bool{true}), Bools("k", []bool{true})}, 101 {"Any:Byte", Any("k", byte(1)), Uint8("k", 1)}, 102 {"Any:Bytes", Any("k", []byte{1}), Binary("k", []byte{1})}, 103 {"Any:Complex128", Any("k", 1+2i), Complex128("k", 1+2i)}, 104 {"Any:Complex128s", Any("k", []complex128{1 + 2i}), Complex128s("k", []complex128{1 + 2i})}, 105 {"Any:Complex64", Any("k", complex64(1+2i)), Complex64("k", 1+2i)}, 106 {"Any:Complex64s", Any("k", []complex64{1 + 2i}), Complex64s("k", []complex64{1 + 2i})}, 107 {"Any:Float64", Any("k", 3.14), Float64("k", 3.14)}, 108 {"Any:Float64s", Any("k", []float64{3.14}), Float64s("k", []float64{3.14})}, 109 {"Any:Float32", Any("k", float32(3.14)), Float32("k", 3.14)}, 110 {"Any:Float32s", Any("k", []float32{3.14}), Float32s("k", []float32{3.14})}, 111 {"Any:Int", Any("k", 1), Int("k", 1)}, 112 {"Any:Ints", Any("k", []int{1}), Ints("k", []int{1})}, 113 {"Any:Int64", Any("k", int64(1)), Int64("k", 1)}, 114 {"Any:Int64s", Any("k", []int64{1}), Int64s("k", []int64{1})}, 115 {"Any:Int32", Any("k", int32(1)), Int32("k", 1)}, 116 {"Any:Int32s", Any("k", []int32{1}), Int32s("k", []int32{1})}, 117 {"Any:Int16", Any("k", int16(1)), Int16("k", 1)}, 118 {"Any:Int16s", Any("k", []int16{1}), Int16s("k", []int16{1})}, 119 {"Any:Int8", Any("k", int8(1)), Int8("k", 1)}, 120 {"Any:Int8s", Any("k", []int8{1}), Int8s("k", []int8{1})}, 121 {"Any:Rune", Any("k", rune(1)), Int32("k", 1)}, 122 {"Any:Runes", Any("k", []rune{1}), Int32s("k", []int32{1})}, 123 {"Any:String", Any("k", "v"), String("k", "v")}, 124 {"Any:Strings", Any("k", []string{"v"}), Strings("k", []string{"v"})}, 125 {"Any:Uint", Any("k", uint(1)), Uint("k", 1)}, 126 {"Any:Uints", Any("k", []uint{1}), Uints("k", []uint{1})}, 127 {"Any:Uint64", Any("k", uint64(1)), Uint64("k", 1)}, 128 {"Any:Uint64s", Any("k", []uint64{1}), Uint64s("k", []uint64{1})}, 129 {"Any:Uint32", Any("k", uint32(1)), Uint32("k", 1)}, 130 {"Any:Uint32s", Any("k", []uint32{1}), Uint32s("k", []uint32{1})}, 131 {"Any:Uint16", Any("k", uint16(1)), Uint16("k", 1)}, 132 {"Any:Uint16s", Any("k", []uint16{1}), Uint16s("k", []uint16{1})}, 133 {"Any:Uint8", Any("k", uint8(1)), Uint8("k", 1)}, 134 {"Any:Uint8s", Any("k", []uint8{1}), Binary("k", []uint8{1})}, 135 {"Any:Uintptr", Any("k", uintptr(1)), Uintptr("k", 1)}, 136 {"Any:Uintptrs", Any("k", []uintptr{1}), Uintptrs("k", []uintptr{1})}, 137 {"Any:Time", Any("k", time.Unix(0, 0)), Time("k", time.Unix(0, 0))}, 138 {"Any:Times", Any("k", []time.Time{time.Unix(0, 0)}), Times("k", []time.Time{time.Unix(0, 0)})}, 139 {"Any:Duration", Any("k", time.Second), Duration("k", time.Second)}, 140 {"Any:Durations", Any("k", []time.Duration{time.Second}), Durations("k", []time.Duration{time.Second})}, 141 {"Any:Fallback", Any("k", struct{}{}), Reflect("k", struct{}{})}, 142 {"Namespace", Namespace("k"), Field{Key: "k", Type: zapcore.NamespaceType}}, 143 } 144 145 for _, tt := range tests { 146 if !assert.Equal(t, tt.expect, tt.field, "Unexpected output from convenience field constructor %s.", tt.name) { 147 t.Logf("type expected: %T\nGot: %T", tt.expect.Interface, tt.field.Interface) 148 } 149 assertCanBeReused(t, tt.field) 150 } 151} 152 153func TestStackField(t *testing.T) { 154 f := Stack("stacktrace") 155 assert.Equal(t, "stacktrace", f.Key, "Unexpected field key.") 156 assert.Equal(t, zapcore.StringType, f.Type, "Unexpected field type.") 157 assert.Equal(t, takeStacktrace(), f.String, "Unexpected stack trace") 158 assertCanBeReused(t, f) 159} 160