github.com/Laisky/zap@v1.27.0/field.go (about) 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 21 package zap 22 23 import ( 24 "fmt" 25 "math" 26 "time" 27 28 "github.com/Laisky/zap/internal/stacktrace" 29 "github.com/Laisky/zap/zapcore" 30 ) 31 32 // Field is an alias for Field. Aliasing this type dramatically 33 // improves the navigability of this package's API documentation. 34 type Field = zapcore.Field 35 36 var ( 37 _minTimeInt64 = time.Unix(0, math.MinInt64) 38 _maxTimeInt64 = time.Unix(0, math.MaxInt64) 39 ) 40 41 // Skip constructs a no-op field, which is often useful when handling invalid 42 // inputs in other Field constructors. 43 func Skip() Field { 44 return Field{Type: zapcore.SkipType} 45 } 46 47 // nilField returns a field which will marshal explicitly as nil. See motivation 48 // in https://github.com/uber-go/zap/issues/753 . If we ever make breaking 49 // changes and add zapcore.NilType and zapcore.ObjectEncoder.AddNil, the 50 // implementation here should be changed to reflect that. 51 func nilField(key string) Field { return Reflect(key, nil) } 52 53 // Binary constructs a field that carries an opaque binary blob. 54 // 55 // Binary data is serialized in an encoding-appropriate format. For example, 56 // zap's JSON encoder base64-encodes binary blobs. To log UTF-8 encoded text, 57 // use ByteString. 58 func Binary(key string, val []byte) Field { 59 return Field{Key: key, Type: zapcore.BinaryType, Interface: val} 60 } 61 62 // Bool constructs a field that carries a bool. 63 func Bool(key string, val bool) Field { 64 var ival int64 65 if val { 66 ival = 1 67 } 68 return Field{Key: key, Type: zapcore.BoolType, Integer: ival} 69 } 70 71 // Boolp constructs a field that carries a *bool. The returned Field will safely 72 // and explicitly represent `nil` when appropriate. 73 func Boolp(key string, val *bool) Field { 74 if val == nil { 75 return nilField(key) 76 } 77 return Bool(key, *val) 78 } 79 80 // ByteString constructs a field that carries UTF-8 encoded text as a []byte. 81 // To log opaque binary blobs (which aren't necessarily valid UTF-8), use 82 // Binary. 83 func ByteString(key string, val []byte) Field { 84 return Field{Key: key, Type: zapcore.ByteStringType, Interface: val} 85 } 86 87 // Complex128 constructs a field that carries a complex number. Unlike most 88 // numeric fields, this costs an allocation (to convert the complex128 to 89 // interface{}). 90 func Complex128(key string, val complex128) Field { 91 return Field{Key: key, Type: zapcore.Complex128Type, Interface: val} 92 } 93 94 // Complex128p constructs a field that carries a *complex128. The returned Field will safely 95 // and explicitly represent `nil` when appropriate. 96 func Complex128p(key string, val *complex128) Field { 97 if val == nil { 98 return nilField(key) 99 } 100 return Complex128(key, *val) 101 } 102 103 // Complex64 constructs a field that carries a complex number. Unlike most 104 // numeric fields, this costs an allocation (to convert the complex64 to 105 // interface{}). 106 func Complex64(key string, val complex64) Field { 107 return Field{Key: key, Type: zapcore.Complex64Type, Interface: val} 108 } 109 110 // Complex64p constructs a field that carries a *complex64. The returned Field will safely 111 // and explicitly represent `nil` when appropriate. 112 func Complex64p(key string, val *complex64) Field { 113 if val == nil { 114 return nilField(key) 115 } 116 return Complex64(key, *val) 117 } 118 119 // Float64 constructs a field that carries a float64. The way the 120 // floating-point value is represented is encoder-dependent, so marshaling is 121 // necessarily lazy. 122 func Float64(key string, val float64) Field { 123 return Field{Key: key, Type: zapcore.Float64Type, Integer: int64(math.Float64bits(val))} 124 } 125 126 // Float64p constructs a field that carries a *float64. The returned Field will safely 127 // and explicitly represent `nil` when appropriate. 128 func Float64p(key string, val *float64) Field { 129 if val == nil { 130 return nilField(key) 131 } 132 return Float64(key, *val) 133 } 134 135 // Float32 constructs a field that carries a float32. The way the 136 // floating-point value is represented is encoder-dependent, so marshaling is 137 // necessarily lazy. 138 func Float32(key string, val float32) Field { 139 return Field{Key: key, Type: zapcore.Float32Type, Integer: int64(math.Float32bits(val))} 140 } 141 142 // Float32p constructs a field that carries a *float32. The returned Field will safely 143 // and explicitly represent `nil` when appropriate. 144 func Float32p(key string, val *float32) Field { 145 if val == nil { 146 return nilField(key) 147 } 148 return Float32(key, *val) 149 } 150 151 // Int constructs a field with the given key and value. 152 func Int(key string, val int) Field { 153 return Int64(key, int64(val)) 154 } 155 156 // Intp constructs a field that carries a *int. The returned Field will safely 157 // and explicitly represent `nil` when appropriate. 158 func Intp(key string, val *int) Field { 159 if val == nil { 160 return nilField(key) 161 } 162 return Int(key, *val) 163 } 164 165 // Int64 constructs a field with the given key and value. 166 func Int64(key string, val int64) Field { 167 return Field{Key: key, Type: zapcore.Int64Type, Integer: val} 168 } 169 170 // Int64p constructs a field that carries a *int64. The returned Field will safely 171 // and explicitly represent `nil` when appropriate. 172 func Int64p(key string, val *int64) Field { 173 if val == nil { 174 return nilField(key) 175 } 176 return Int64(key, *val) 177 } 178 179 // Int32 constructs a field with the given key and value. 180 func Int32(key string, val int32) Field { 181 return Field{Key: key, Type: zapcore.Int32Type, Integer: int64(val)} 182 } 183 184 // Int32p constructs a field that carries a *int32. The returned Field will safely 185 // and explicitly represent `nil` when appropriate. 186 func Int32p(key string, val *int32) Field { 187 if val == nil { 188 return nilField(key) 189 } 190 return Int32(key, *val) 191 } 192 193 // Int16 constructs a field with the given key and value. 194 func Int16(key string, val int16) Field { 195 return Field{Key: key, Type: zapcore.Int16Type, Integer: int64(val)} 196 } 197 198 // Int16p constructs a field that carries a *int16. The returned Field will safely 199 // and explicitly represent `nil` when appropriate. 200 func Int16p(key string, val *int16) Field { 201 if val == nil { 202 return nilField(key) 203 } 204 return Int16(key, *val) 205 } 206 207 // Int8 constructs a field with the given key and value. 208 func Int8(key string, val int8) Field { 209 return Field{Key: key, Type: zapcore.Int8Type, Integer: int64(val)} 210 } 211 212 // Int8p constructs a field that carries a *int8. The returned Field will safely 213 // and explicitly represent `nil` when appropriate. 214 func Int8p(key string, val *int8) Field { 215 if val == nil { 216 return nilField(key) 217 } 218 return Int8(key, *val) 219 } 220 221 // String constructs a field with the given key and value. 222 func String(key string, val string) Field { 223 return Field{Key: key, Type: zapcore.StringType, String: val} 224 } 225 226 // Stringp constructs a field that carries a *string. The returned Field will safely 227 // and explicitly represent `nil` when appropriate. 228 func Stringp(key string, val *string) Field { 229 if val == nil { 230 return nilField(key) 231 } 232 return String(key, *val) 233 } 234 235 // Uint constructs a field with the given key and value. 236 func Uint(key string, val uint) Field { 237 return Uint64(key, uint64(val)) 238 } 239 240 // Uintp constructs a field that carries a *uint. The returned Field will safely 241 // and explicitly represent `nil` when appropriate. 242 func Uintp(key string, val *uint) Field { 243 if val == nil { 244 return nilField(key) 245 } 246 return Uint(key, *val) 247 } 248 249 // Uint64 constructs a field with the given key and value. 250 func Uint64(key string, val uint64) Field { 251 return Field{Key: key, Type: zapcore.Uint64Type, Integer: int64(val)} 252 } 253 254 // Uint64p constructs a field that carries a *uint64. The returned Field will safely 255 // and explicitly represent `nil` when appropriate. 256 func Uint64p(key string, val *uint64) Field { 257 if val == nil { 258 return nilField(key) 259 } 260 return Uint64(key, *val) 261 } 262 263 // Uint32 constructs a field with the given key and value. 264 func Uint32(key string, val uint32) Field { 265 return Field{Key: key, Type: zapcore.Uint32Type, Integer: int64(val)} 266 } 267 268 // Uint32p constructs a field that carries a *uint32. The returned Field will safely 269 // and explicitly represent `nil` when appropriate. 270 func Uint32p(key string, val *uint32) Field { 271 if val == nil { 272 return nilField(key) 273 } 274 return Uint32(key, *val) 275 } 276 277 // Uint16 constructs a field with the given key and value. 278 func Uint16(key string, val uint16) Field { 279 return Field{Key: key, Type: zapcore.Uint16Type, Integer: int64(val)} 280 } 281 282 // Uint16p constructs a field that carries a *uint16. The returned Field will safely 283 // and explicitly represent `nil` when appropriate. 284 func Uint16p(key string, val *uint16) Field { 285 if val == nil { 286 return nilField(key) 287 } 288 return Uint16(key, *val) 289 } 290 291 // Uint8 constructs a field with the given key and value. 292 func Uint8(key string, val uint8) Field { 293 return Field{Key: key, Type: zapcore.Uint8Type, Integer: int64(val)} 294 } 295 296 // Uint8p constructs a field that carries a *uint8. The returned Field will safely 297 // and explicitly represent `nil` when appropriate. 298 func Uint8p(key string, val *uint8) Field { 299 if val == nil { 300 return nilField(key) 301 } 302 return Uint8(key, *val) 303 } 304 305 // Uintptr constructs a field with the given key and value. 306 func Uintptr(key string, val uintptr) Field { 307 return Field{Key: key, Type: zapcore.UintptrType, Integer: int64(val)} 308 } 309 310 // Uintptrp constructs a field that carries a *uintptr. The returned Field will safely 311 // and explicitly represent `nil` when appropriate. 312 func Uintptrp(key string, val *uintptr) Field { 313 if val == nil { 314 return nilField(key) 315 } 316 return Uintptr(key, *val) 317 } 318 319 // Reflect constructs a field with the given key and an arbitrary object. It uses 320 // an encoding-appropriate, reflection-based function to lazily serialize nearly 321 // any object into the logging context, but it's relatively slow and 322 // allocation-heavy. Outside tests, Any is always a better choice. 323 // 324 // If encoding fails (e.g., trying to serialize a map[int]string to JSON), Reflect 325 // includes the error message in the final log output. 326 func Reflect(key string, val interface{}) Field { 327 return Field{Key: key, Type: zapcore.ReflectType, Interface: val} 328 } 329 330 // Namespace creates a named, isolated scope within the logger's context. All 331 // subsequent fields will be added to the new namespace. 332 // 333 // This helps prevent key collisions when injecting loggers into sub-components 334 // or third-party libraries. 335 func Namespace(key string) Field { 336 return Field{Key: key, Type: zapcore.NamespaceType} 337 } 338 339 // Stringer constructs a field with the given key and the output of the value's 340 // String method. The Stringer's String method is called lazily. 341 func Stringer(key string, val fmt.Stringer) Field { 342 return Field{Key: key, Type: zapcore.StringerType, Interface: val} 343 } 344 345 // Time constructs a Field with the given key and value. The encoder 346 // controls how the time is serialized. 347 func Time(key string, val time.Time) Field { 348 if val.Before(_minTimeInt64) || val.After(_maxTimeInt64) { 349 return Field{Key: key, Type: zapcore.TimeFullType, Interface: val} 350 } 351 return Field{Key: key, Type: zapcore.TimeType, Integer: val.UnixNano(), Interface: val.Location()} 352 } 353 354 // Timep constructs a field that carries a *time.Time. The returned Field will safely 355 // and explicitly represent `nil` when appropriate. 356 func Timep(key string, val *time.Time) Field { 357 if val == nil { 358 return nilField(key) 359 } 360 return Time(key, *val) 361 } 362 363 // Stack constructs a field that stores a stacktrace of the current goroutine 364 // under provided key. Keep in mind that taking a stacktrace is eager and 365 // expensive (relatively speaking); this function both makes an allocation and 366 // takes about two microseconds. 367 func Stack(key string) Field { 368 return StackSkip(key, 1) // skip Stack 369 } 370 371 // StackSkip constructs a field similarly to Stack, but also skips the given 372 // number of frames from the top of the stacktrace. 373 func StackSkip(key string, skip int) Field { 374 // Returning the stacktrace as a string costs an allocation, but saves us 375 // from expanding the zapcore.Field union struct to include a byte slice. Since 376 // taking a stacktrace is already so expensive (~10us), the extra allocation 377 // is okay. 378 return String(key, stacktrace.Take(skip+1)) // skip StackSkip 379 } 380 381 // Duration constructs a field with the given key and value. The encoder 382 // controls how the duration is serialized. 383 func Duration(key string, val time.Duration) Field { 384 return Field{Key: key, Type: zapcore.DurationType, Integer: int64(val)} 385 } 386 387 // Durationp constructs a field that carries a *time.Duration. The returned Field will safely 388 // and explicitly represent `nil` when appropriate. 389 func Durationp(key string, val *time.Duration) Field { 390 if val == nil { 391 return nilField(key) 392 } 393 return Duration(key, *val) 394 } 395 396 // Object constructs a field with the given key and ObjectMarshaler. It 397 // provides a flexible, but still type-safe and efficient, way to add map- or 398 // struct-like user-defined types to the logging context. The struct's 399 // MarshalLogObject method is called lazily. 400 func Object(key string, val zapcore.ObjectMarshaler) Field { 401 return Field{Key: key, Type: zapcore.ObjectMarshalerType, Interface: val} 402 } 403 404 // Inline constructs a Field that is similar to Object, but it 405 // will add the elements of the provided ObjectMarshaler to the 406 // current namespace. 407 func Inline(val zapcore.ObjectMarshaler) Field { 408 return zapcore.Field{ 409 Type: zapcore.InlineMarshalerType, 410 Interface: val, 411 } 412 } 413 414 // Dict constructs a field containing the provided key-value pairs. 415 // It acts similar to [Object], but with the fields specified as arguments. 416 func Dict(key string, val ...Field) Field { 417 return dictField(key, val) 418 } 419 420 // We need a function with the signature (string, T) for zap.Any. 421 func dictField(key string, val []Field) Field { 422 return Object(key, dictObject(val)) 423 } 424 425 type dictObject []Field 426 427 func (d dictObject) MarshalLogObject(enc zapcore.ObjectEncoder) error { 428 for _, f := range d { 429 f.AddTo(enc) 430 } 431 return nil 432 } 433 434 // We discovered an issue where zap.Any can cause a performance degradation 435 // when used in new goroutines. 436 // 437 // This happens because the compiler assigns 4.8kb (one zap.Field per arm of 438 // switch statement) of stack space for zap.Any when it takes the form: 439 // 440 // switch v := v.(type) { 441 // case string: 442 // return String(key, v) 443 // case int: 444 // return Int(key, v) 445 // // ... 446 // default: 447 // return Reflect(key, v) 448 // } 449 // 450 // To avoid this, we use the type switch to assign a value to a single local variable 451 // and then call a function on it. 452 // The local variable is just a function reference so it doesn't allocate 453 // when converted to an interface{}. 454 // 455 // A fair bit of experimentation went into this. 456 // See also: 457 // 458 // - https://github.com/uber-go/zap/pull/1301 459 // - https://github.com/uber-go/zap/pull/1303 460 // - https://github.com/uber-go/zap/pull/1304 461 // - https://github.com/uber-go/zap/pull/1305 462 // - https://github.com/uber-go/zap/pull/1308 463 // 464 // See https://github.com/golang/go/issues/62077 for upstream issue. 465 type anyFieldC[T any] func(string, T) Field 466 467 func (f anyFieldC[T]) Any(key string, val any) Field { 468 v, _ := val.(T) 469 // val is guaranteed to be a T, except when it's nil. 470 return f(key, v) 471 } 472 473 // Any takes a key and an arbitrary value and chooses the best way to represent 474 // them as a field, falling back to a reflection-based approach only if 475 // necessary. 476 // 477 // Since byte/uint8 and rune/int32 are aliases, Any can't differentiate between 478 // them. To minimize surprises, []byte values are treated as binary blobs, byte 479 // values are treated as uint8, and runes are always treated as integers. 480 func Any(key string, value interface{}) Field { 481 var c interface{ Any(string, any) Field } 482 483 switch value.(type) { 484 case zapcore.ObjectMarshaler: 485 c = anyFieldC[zapcore.ObjectMarshaler](Object) 486 case zapcore.ArrayMarshaler: 487 c = anyFieldC[zapcore.ArrayMarshaler](Array) 488 case []Field: 489 c = anyFieldC[[]Field](dictField) 490 case bool: 491 c = anyFieldC[bool](Bool) 492 case *bool: 493 c = anyFieldC[*bool](Boolp) 494 case []bool: 495 c = anyFieldC[[]bool](Bools) 496 case complex128: 497 c = anyFieldC[complex128](Complex128) 498 case *complex128: 499 c = anyFieldC[*complex128](Complex128p) 500 case []complex128: 501 c = anyFieldC[[]complex128](Complex128s) 502 case complex64: 503 c = anyFieldC[complex64](Complex64) 504 case *complex64: 505 c = anyFieldC[*complex64](Complex64p) 506 case []complex64: 507 c = anyFieldC[[]complex64](Complex64s) 508 case float64: 509 c = anyFieldC[float64](Float64) 510 case *float64: 511 c = anyFieldC[*float64](Float64p) 512 case []float64: 513 c = anyFieldC[[]float64](Float64s) 514 case float32: 515 c = anyFieldC[float32](Float32) 516 case *float32: 517 c = anyFieldC[*float32](Float32p) 518 case []float32: 519 c = anyFieldC[[]float32](Float32s) 520 case int: 521 c = anyFieldC[int](Int) 522 case *int: 523 c = anyFieldC[*int](Intp) 524 case []int: 525 c = anyFieldC[[]int](Ints) 526 case int64: 527 c = anyFieldC[int64](Int64) 528 case *int64: 529 c = anyFieldC[*int64](Int64p) 530 case []int64: 531 c = anyFieldC[[]int64](Int64s) 532 case int32: 533 c = anyFieldC[int32](Int32) 534 case *int32: 535 c = anyFieldC[*int32](Int32p) 536 case []int32: 537 c = anyFieldC[[]int32](Int32s) 538 case int16: 539 c = anyFieldC[int16](Int16) 540 case *int16: 541 c = anyFieldC[*int16](Int16p) 542 case []int16: 543 c = anyFieldC[[]int16](Int16s) 544 case int8: 545 c = anyFieldC[int8](Int8) 546 case *int8: 547 c = anyFieldC[*int8](Int8p) 548 case []int8: 549 c = anyFieldC[[]int8](Int8s) 550 case string: 551 c = anyFieldC[string](String) 552 case *string: 553 c = anyFieldC[*string](Stringp) 554 case []string: 555 c = anyFieldC[[]string](Strings) 556 case uint: 557 c = anyFieldC[uint](Uint) 558 case *uint: 559 c = anyFieldC[*uint](Uintp) 560 case []uint: 561 c = anyFieldC[[]uint](Uints) 562 case uint64: 563 c = anyFieldC[uint64](Uint64) 564 case *uint64: 565 c = anyFieldC[*uint64](Uint64p) 566 case []uint64: 567 c = anyFieldC[[]uint64](Uint64s) 568 case uint32: 569 c = anyFieldC[uint32](Uint32) 570 case *uint32: 571 c = anyFieldC[*uint32](Uint32p) 572 case []uint32: 573 c = anyFieldC[[]uint32](Uint32s) 574 case uint16: 575 c = anyFieldC[uint16](Uint16) 576 case *uint16: 577 c = anyFieldC[*uint16](Uint16p) 578 case []uint16: 579 c = anyFieldC[[]uint16](Uint16s) 580 case uint8: 581 c = anyFieldC[uint8](Uint8) 582 case *uint8: 583 c = anyFieldC[*uint8](Uint8p) 584 case []byte: 585 c = anyFieldC[[]byte](Binary) 586 case uintptr: 587 c = anyFieldC[uintptr](Uintptr) 588 case *uintptr: 589 c = anyFieldC[*uintptr](Uintptrp) 590 case []uintptr: 591 c = anyFieldC[[]uintptr](Uintptrs) 592 case time.Time: 593 c = anyFieldC[time.Time](Time) 594 case *time.Time: 595 c = anyFieldC[*time.Time](Timep) 596 case []time.Time: 597 c = anyFieldC[[]time.Time](Times) 598 case time.Duration: 599 c = anyFieldC[time.Duration](Duration) 600 case *time.Duration: 601 c = anyFieldC[*time.Duration](Durationp) 602 case []time.Duration: 603 c = anyFieldC[[]time.Duration](Durations) 604 case error: 605 c = anyFieldC[error](NamedError) 606 case []error: 607 c = anyFieldC[[]error](Errors) 608 case fmt.Stringer: 609 c = anyFieldC[fmt.Stringer](Stringer) 610 default: 611 c = anyFieldC[any](Reflect) 612 } 613 614 return c.Any(key, value) 615 }