github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/zlog/logfmt_encoder.go (about) 1 package zlog 2 3 // This file is forked from https://github.com/jsternberg/zap-logfmt. 4 // It's originally published by Jonathan A. Sternberg with MIT license. 5 6 import ( 7 "bytes" 8 "encoding/base64" 9 "errors" 10 "fmt" 11 "math" 12 "reflect" 13 "strings" 14 "sync" 15 "time" 16 "unicode/utf8" 17 18 "go.uber.org/zap/buffer" 19 "go.uber.org/zap/zapcore" 20 ) 21 22 const ( 23 // For JSON-escaping; see logfmtEncoder.safeAddString below. 24 _hex = "0123456789abcdef" 25 ) 26 27 var ( 28 bufferpool = buffer.NewPool() 29 logfmtPool = sync.Pool{New: func() any { 30 return &logfmtEncoder{} 31 }} 32 ) 33 34 var ErrUnsupportedValueType = errors.New("unsupported value type") 35 36 func getEncoder() *logfmtEncoder { 37 return logfmtPool.Get().(*logfmtEncoder) 38 } 39 40 func putEncoder(enc *logfmtEncoder) { 41 enc.EncoderConfig = nil 42 enc.buf = nil 43 logfmtPool.Put(enc) 44 } 45 46 type logfmtEncoder struct { 47 *zapcore.EncoderConfig 48 buf *buffer.Buffer 49 namespaces []string 50 } 51 52 // NewLogfmtEncoder creates a [zapcore.Encoder] which encodes log in the 53 // "logfmt" format. 54 // The returned encoder does not support [zapcore.ObjectMarshaler]. 55 func NewLogfmtEncoder(cfg zapcore.EncoderConfig) zapcore.Encoder { 56 return &logfmtEncoder{ 57 EncoderConfig: &cfg, 58 buf: bufferpool.Get(), 59 } 60 } 61 62 func (enc *logfmtEncoder) AddArray(key string, arr zapcore.ArrayMarshaler) error { 63 enc.addKey(key) 64 return enc.AppendArray(arr) 65 } 66 67 func (enc *logfmtEncoder) AddObject(key string, obj zapcore.ObjectMarshaler) error { 68 _, _ = key, obj 69 return ErrUnsupportedValueType 70 } 71 72 func (enc *logfmtEncoder) AddBinary(key string, value []byte) { 73 enc.AddString(key, base64.StdEncoding.EncodeToString(value)) 74 } 75 76 func (enc *logfmtEncoder) AddByteString(key string, value []byte) { 77 enc.addKey(key) 78 enc.AppendByteString(value) 79 } 80 81 func (enc *logfmtEncoder) AddBool(key string, value bool) { 82 enc.addKey(key) 83 enc.AppendBool(value) 84 } 85 86 func (enc *logfmtEncoder) AddComplex128(key string, value complex128) { 87 enc.addKey(key) 88 enc.AppendComplex128(value) 89 } 90 91 func (enc *logfmtEncoder) AddDuration(key string, value time.Duration) { 92 enc.addKey(key) 93 enc.AppendDuration(value) 94 } 95 96 func (enc *logfmtEncoder) AddFloat64(key string, value float64) { 97 enc.addKey(key) 98 enc.AppendFloat64(value) 99 } 100 101 func (enc *logfmtEncoder) AddInt64(key string, value int64) { 102 enc.addKey(key) 103 enc.AppendInt64(value) 104 } 105 106 func (enc *logfmtEncoder) AddReflected(key string, value any) error { 107 enc.addKey(key) 108 return enc.AppendReflected(value) 109 } 110 111 func (enc *logfmtEncoder) OpenNamespace(key string) { 112 enc.namespaces = append(enc.namespaces, key) 113 } 114 115 func (enc *logfmtEncoder) AddString(key, value string) { 116 enc.addKey(key) 117 enc.AppendString(value) 118 } 119 120 func (enc *logfmtEncoder) AddTime(key string, value time.Time) { 121 enc.addKeyWithoutNamespace(key) 122 enc.AppendTime(value) 123 } 124 125 func (enc *logfmtEncoder) AddUint64(key string, value uint64) { 126 enc.addKey(key) 127 enc.AppendUint64(value) 128 } 129 130 func (enc *logfmtEncoder) AppendArray(arr zapcore.ArrayMarshaler) error { 131 marshaler := literalEncoder{ 132 EncoderConfig: enc.EncoderConfig, 133 buf: bufferpool.Get(), 134 } 135 136 err := arr.MarshalLogArray(&marshaler) 137 if err == nil { 138 enc.AppendByteString(marshaler.buf.Bytes()) 139 } else { 140 enc.AppendByteString(nil) 141 } 142 marshaler.buf.Free() 143 return err 144 } 145 146 func (enc *logfmtEncoder) AppendObject(obj zapcore.ObjectMarshaler) error { 147 _ = obj 148 return ErrUnsupportedValueType 149 } 150 151 func (enc *logfmtEncoder) AppendBool(value bool) { 152 if value { 153 enc.AppendString("true") 154 } else { 155 enc.AppendString("false") 156 } 157 } 158 159 func (enc *logfmtEncoder) AppendByteString(value []byte) { 160 needsQuotes := bytes.IndexFunc(value, needsQuotedValueRune) != -1 161 if needsQuotes { 162 enc.buf.AppendByte('"') 163 } 164 enc.safeAddByteString(value) 165 if needsQuotes { 166 enc.buf.AppendByte('"') 167 } 168 } 169 170 func (enc *logfmtEncoder) AppendComplex128(value complex128) { 171 // Cast to a platform-independent, fixed-size type. 172 r, i := real(value), imag(value) 173 enc.buf.AppendFloat(r, 64) 174 enc.buf.AppendByte('+') 175 enc.buf.AppendFloat(i, 64) 176 enc.buf.AppendByte('i') 177 } 178 179 func (enc *logfmtEncoder) AppendDuration(value time.Duration) { 180 cur := enc.buf.Len() 181 enc.EncodeDuration(value, enc) 182 if cur == enc.buf.Len() { 183 // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds. 184 enc.AppendInt64(int64(value)) 185 } 186 } 187 188 func (enc *logfmtEncoder) AppendInt64(value int64) { 189 enc.buf.AppendInt(value) 190 } 191 192 func (enc *logfmtEncoder) AppendReflected(value any) error { 193 rvalue := reflect.ValueOf(value) 194 switch rvalue.Kind() { 195 case reflect.Chan, reflect.Func, reflect.Map, reflect.Struct: 196 return ErrUnsupportedValueType 197 case reflect.Array: 198 return enc.AppendArray(enc.marshalArray(rvalue)) 199 case reflect.Slice: 200 if rvalue.IsNil() { 201 enc.AppendByteString(nil) 202 return nil 203 } 204 // A non-nil slice is handled identically to an array. 205 return enc.AppendArray(enc.marshalArray(rvalue)) 206 case reflect.Ptr: 207 if rvalue.IsNil() { 208 enc.AppendByteString(nil) 209 return nil 210 } 211 return enc.AppendReflected(rvalue.Elem().Interface()) 212 } 213 enc.AppendString(fmt.Sprint(value)) 214 return nil 215 } 216 217 func (enc *logfmtEncoder) marshalArray(rv reflect.Value) zapcore.ArrayMarshalerFunc { 218 return func(ae zapcore.ArrayEncoder) error { 219 for i, n := 0, rv.Len(); i < n; i++ { 220 v := rv.Index(i).Interface() 221 if err := ae.AppendReflected(v); err != nil { 222 return err 223 } 224 } 225 return nil 226 } 227 } 228 229 func (enc *logfmtEncoder) AppendString(value string) { 230 needsQuotes := strings.IndexFunc(value, needsQuotedValueRune) != -1 231 if needsQuotes { 232 enc.buf.AppendByte('"') 233 } 234 enc.safeAddString(value) 235 if needsQuotes { 236 enc.buf.AppendByte('"') 237 } 238 } 239 240 func (enc *logfmtEncoder) AppendTime(value time.Time) { 241 cur := enc.buf.Len() 242 enc.EncodeTime(value, enc) 243 if cur == enc.buf.Len() { 244 enc.AppendInt64(value.UnixNano()) 245 } 246 } 247 248 func (enc *logfmtEncoder) AppendUint64(value uint64) { 249 enc.buf.AppendUint(value) 250 } 251 252 func (enc *logfmtEncoder) AddComplex64(k string, v complex64) { enc.AddComplex128(k, complex128(v)) } 253 func (enc *logfmtEncoder) AddFloat32(k string, v float32) { enc.AddFloat64(k, float64(v)) } 254 func (enc *logfmtEncoder) AddInt(k string, v int) { enc.AddInt64(k, int64(v)) } 255 func (enc *logfmtEncoder) AddInt32(k string, v int32) { enc.AddInt64(k, int64(v)) } 256 func (enc *logfmtEncoder) AddInt16(k string, v int16) { enc.AddInt64(k, int64(v)) } 257 func (enc *logfmtEncoder) AddInt8(k string, v int8) { enc.AddInt64(k, int64(v)) } 258 func (enc *logfmtEncoder) AddUint(k string, v uint) { enc.AddUint64(k, uint64(v)) } 259 func (enc *logfmtEncoder) AddUint32(k string, v uint32) { enc.AddUint64(k, uint64(v)) } 260 func (enc *logfmtEncoder) AddUint16(k string, v uint16) { enc.AddUint64(k, uint64(v)) } 261 func (enc *logfmtEncoder) AddUint8(k string, v uint8) { enc.AddUint64(k, uint64(v)) } 262 func (enc *logfmtEncoder) AddUintptr(k string, v uintptr) { enc.AddUint64(k, uint64(v)) } 263 func (enc *logfmtEncoder) AppendComplex64(v complex64) { enc.AppendComplex128(complex128(v)) } 264 func (enc *logfmtEncoder) AppendFloat64(v float64) { enc.appendFloat(v, 64) } 265 func (enc *logfmtEncoder) AppendFloat32(v float32) { enc.appendFloat(float64(v), 32) } 266 func (enc *logfmtEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } 267 func (enc *logfmtEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } 268 func (enc *logfmtEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } 269 func (enc *logfmtEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } 270 func (enc *logfmtEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } 271 func (enc *logfmtEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } 272 func (enc *logfmtEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } 273 func (enc *logfmtEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } 274 func (enc *logfmtEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } 275 276 func (enc *logfmtEncoder) Clone() zapcore.Encoder { 277 clone := enc.clone() 278 clone.buf.Write(enc.buf.Bytes()) 279 return clone 280 } 281 282 func (enc *logfmtEncoder) clone() *logfmtEncoder { 283 clone := getEncoder() 284 clone.EncoderConfig = enc.EncoderConfig 285 clone.buf = bufferpool.Get() 286 clone.namespaces = enc.namespaces 287 return clone 288 } 289 290 func (enc *logfmtEncoder) EncodeEntry(ent zapcore.Entry, fields []zapcore.Field) (*buffer.Buffer, error) { 291 final := enc.clone() 292 if final.TimeKey != "" { 293 final.AddTime(final.TimeKey, ent.Time) 294 } 295 if final.LevelKey != "" { 296 final.addKeyWithoutNamespace(final.LevelKey) 297 cur := final.buf.Len() 298 final.EncodeLevel(ent.Level, final) 299 if cur == final.buf.Len() { 300 // User-supplied EncodeLevel was a no-op. Fall back to strings to keep 301 // output valid. 302 final.AppendString(ent.Level.String()) 303 } 304 } 305 if ent.LoggerName != "" && final.NameKey != "" { 306 final.addKeyWithoutNamespace(final.NameKey) 307 cur := final.buf.Len() 308 nameEncoder := final.EncodeName 309 if nameEncoder == nil { 310 nameEncoder = zapcore.FullNameEncoder 311 } 312 nameEncoder(ent.LoggerName, final) 313 if cur == final.buf.Len() { 314 // User-supplied EncodeName was a no-op. Fall back to strings to 315 // keep output valid. 316 final.AppendString(ent.LoggerName) 317 } 318 } 319 if ent.Caller.Defined && final.CallerKey != "" { 320 final.addKeyWithoutNamespace(final.CallerKey) 321 cur := final.buf.Len() 322 final.EncodeCaller(ent.Caller, final) 323 if cur == final.buf.Len() { 324 // User-supplied EncodeCaller was a no-op. Fall back to strings to 325 // keep output valid. 326 final.AppendString(ent.Caller.String()) 327 } 328 } 329 if final.MessageKey != "" { 330 final.addKeyWithoutNamespace(enc.MessageKey) 331 final.AppendString(ent.Message) 332 } 333 if enc.buf.Len() > 0 { 334 final.buf.AppendByte(' ') 335 final.buf.Write(enc.buf.Bytes()) 336 } 337 addFields(final, fields) 338 if ent.Stack != "" && final.StacktraceKey != "" { 339 final.addKeyWithoutNamespace(final.StacktraceKey) 340 final.AppendString(ent.Stack) 341 } 342 if final.LineEnding != "" { 343 final.buf.AppendString(final.LineEnding) 344 } else { 345 final.buf.AppendString(zapcore.DefaultLineEnding) 346 } 347 348 ret := final.buf 349 putEncoder(final) 350 return ret, nil 351 } 352 353 func (enc *logfmtEncoder) truncate() { 354 enc.buf.Reset() 355 enc.namespaces = nil 356 } 357 358 func (enc *logfmtEncoder) addKey(key string) { 359 if enc.buf.Len() > 0 { 360 enc.buf.AppendByte(' ') 361 } 362 for _, ns := range enc.namespaces { 363 enc.safeAddString(ns) 364 enc.buf.AppendByte('.') 365 } 366 enc.safeAddString(key) 367 enc.buf.AppendByte('=') 368 } 369 370 func (enc *logfmtEncoder) addKeyWithoutNamespace(key string) { 371 if enc.buf.Len() > 0 { 372 enc.buf.AppendByte(' ') 373 } 374 enc.safeAddString(key) 375 enc.buf.AppendByte('=') 376 } 377 378 func (enc *logfmtEncoder) appendFloat(val float64, bitSize int) { 379 switch { 380 case math.IsNaN(val): 381 enc.buf.AppendString(`NaN`) 382 case math.IsInf(val, 1): 383 enc.buf.AppendString(`+Inf`) 384 case math.IsInf(val, -1): 385 enc.buf.AppendString(`-Inf`) 386 default: 387 enc.buf.AppendFloat(val, bitSize) 388 } 389 } 390 391 // safeAddString JSON-escapes a string and appends it to the internal buffer. 392 // Unlike the standard library's encoder, it doesn't attempt to protect the 393 // user from browser vulnerabilities or JSONP-related problems. 394 func (enc *logfmtEncoder) safeAddString(s string) { 395 for i := 0; i < len(s); { 396 if enc.tryAddRuneSelf(s[i]) { 397 i++ 398 continue 399 } 400 r, size := utf8.DecodeRuneInString(s[i:]) 401 if enc.tryAddRuneError(r, size) { 402 i++ 403 continue 404 } 405 enc.buf.AppendString(s[i : i+size]) 406 i += size 407 } 408 } 409 410 // safeAddByteString is no-alloc equivalent of safeAddString(string(s)) for s []byte. 411 func (enc *logfmtEncoder) safeAddByteString(s []byte) { 412 for i := 0; i < len(s); { 413 if enc.tryAddRuneSelf(s[i]) { 414 i++ 415 continue 416 } 417 r, size := utf8.DecodeRune(s[i:]) 418 if enc.tryAddRuneError(r, size) { 419 i++ 420 continue 421 } 422 enc.buf.Write(s[i : i+size]) 423 i += size 424 } 425 } 426 427 // tryAddRuneSelf appends b if it is valid UTF-8 character represented in a single byte. 428 func (enc *logfmtEncoder) tryAddRuneSelf(b byte) bool { 429 if b >= utf8.RuneSelf { 430 return false 431 } 432 if 0x20 <= b && b != '\\' && b != '"' { 433 enc.buf.AppendByte(b) 434 return true 435 } 436 switch b { 437 case '\\', '"': 438 enc.buf.AppendByte('\\') 439 enc.buf.AppendByte(b) 440 case '\n': 441 enc.buf.AppendByte('\\') 442 enc.buf.AppendByte('n') 443 case '\r': 444 enc.buf.AppendByte('\\') 445 enc.buf.AppendByte('r') 446 case '\t': 447 enc.buf.AppendByte('\\') 448 enc.buf.AppendByte('t') 449 default: 450 // Encode bytes < 0x20, except for the escape sequences above. 451 enc.buf.AppendString(`\u00`) 452 enc.buf.AppendByte(_hex[b>>4]) 453 enc.buf.AppendByte(_hex[b&0xF]) 454 } 455 return true 456 } 457 458 func (enc *logfmtEncoder) tryAddRuneError(r rune, size int) bool { 459 if r == utf8.RuneError && size == 1 { 460 enc.buf.AppendString(`\ufffd`) 461 return true 462 } 463 return false 464 } 465 466 type literalEncoder struct { 467 *zapcore.EncoderConfig 468 buf *buffer.Buffer 469 } 470 471 func (enc *literalEncoder) AppendBool(value bool) { 472 enc.addSeparator() 473 if value { 474 enc.AppendString("true") 475 } else { 476 enc.AppendString("false") 477 } 478 } 479 480 func (enc *literalEncoder) AppendByteString(value []byte) { 481 enc.addSeparator() 482 enc.buf.AppendString(string(value)) 483 } 484 485 func (enc *literalEncoder) AppendComplex128(value complex128) { 486 enc.addSeparator() 487 // Cast to a platform-independent, fixed-size type. 488 r, i := real(value), imag(value) 489 enc.buf.AppendFloat(r, 64) 490 enc.buf.AppendByte('+') 491 enc.buf.AppendFloat(i, 64) 492 enc.buf.AppendByte('i') 493 } 494 495 func (enc *literalEncoder) AppendComplex64(value complex64) { 496 enc.AppendComplex128(complex128(value)) 497 } 498 499 func (enc *literalEncoder) AppendFloat64(value float64) { 500 enc.addSeparator() 501 enc.buf.AppendFloat(value, 64) 502 } 503 504 func (enc *literalEncoder) AppendFloat32(value float32) { 505 enc.addSeparator() 506 enc.buf.AppendFloat(float64(value), 32) 507 } 508 509 func (enc *literalEncoder) AppendInt64(value int64) { 510 enc.addSeparator() 511 enc.buf.AppendInt(value) 512 } 513 514 func (enc *literalEncoder) AppendInt(v int) { enc.AppendInt64(int64(v)) } 515 func (enc *literalEncoder) AppendInt32(v int32) { enc.AppendInt64(int64(v)) } 516 func (enc *literalEncoder) AppendInt16(v int16) { enc.AppendInt64(int64(v)) } 517 func (enc *literalEncoder) AppendInt8(v int8) { enc.AppendInt64(int64(v)) } 518 519 func (enc *literalEncoder) AppendString(value string) { 520 enc.addSeparator() 521 enc.buf.AppendString(value) 522 } 523 524 func (enc *literalEncoder) AppendUint64(value uint64) { 525 enc.addSeparator() 526 enc.buf.AppendUint(value) 527 } 528 529 func (enc *literalEncoder) AppendUint(v uint) { enc.AppendUint64(uint64(v)) } 530 func (enc *literalEncoder) AppendUint32(v uint32) { enc.AppendUint64(uint64(v)) } 531 func (enc *literalEncoder) AppendUint16(v uint16) { enc.AppendUint64(uint64(v)) } 532 func (enc *literalEncoder) AppendUint8(v uint8) { enc.AppendUint64(uint64(v)) } 533 func (enc *literalEncoder) AppendUintptr(v uintptr) { enc.AppendUint64(uint64(v)) } 534 535 func (enc *literalEncoder) AppendDuration(value time.Duration) { 536 cur := enc.buf.Len() 537 enc.EncodeDuration(value, enc) 538 if cur == enc.buf.Len() { 539 // User-supplied EncodeDuration is a no-op. Fall back to nanoseconds. 540 enc.AppendInt64(int64(value)) 541 } 542 } 543 544 func (enc *literalEncoder) AppendTime(value time.Time) { 545 cur := enc.buf.Len() 546 enc.EncodeTime(value, enc) 547 if cur == enc.buf.Len() { 548 enc.AppendInt64(value.UnixNano()) 549 } 550 } 551 552 func (enc *literalEncoder) AppendArray(arr zapcore.ArrayMarshaler) error { 553 return arr.MarshalLogArray(enc) 554 } 555 556 func (enc *literalEncoder) AppendObject(zapcore.ObjectMarshaler) error { 557 return ErrUnsupportedValueType 558 } 559 560 func (enc *literalEncoder) AppendReflected(value any) error { 561 typ := reflect.TypeOf(value) 562 switch typ.Kind() { 563 case reflect.Bool: 564 enc.AppendBool(value.(bool)) 565 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 566 enc.AppendInt64(reflect.ValueOf(value).Int()) 567 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: 568 enc.AppendUint64(reflect.ValueOf(value).Uint()) 569 case reflect.Float32: 570 enc.AppendFloat32(value.(float32)) 571 case reflect.Float64: 572 enc.AppendFloat64(value.(float64)) 573 case reflect.Complex64: 574 enc.AppendComplex64(value.(complex64)) 575 case reflect.Complex128: 576 enc.AppendComplex128(value.(complex128)) 577 case reflect.String: 578 enc.AppendString(value.(string)) 579 default: 580 return ErrUnsupportedValueType 581 } 582 return nil 583 } 584 585 func (enc *literalEncoder) addSeparator() { 586 if enc.buf.Len() > 0 { 587 enc.buf.AppendByte(',') 588 } 589 } 590 591 func needsQuotedValueRune(r rune) bool { 592 return r <= ' ' || r == '=' || r == '"' || r == utf8.RuneError 593 } 594 595 func addFields(enc zapcore.ObjectEncoder, fields []zapcore.Field) { 596 for i := range fields { 597 fields[i].AddTo(enc) 598 } 599 }