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