123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- // Copyright (c) 2016 Uber Technologies, Inc.
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- // THE SOFTWARE.
- package zapcore
- import (
- "fmt"
- "sync"
- "go.uber.org/zap/buffer"
- "go.uber.org/zap/internal/bufferpool"
- )
- var _sliceEncoderPool = sync.Pool{
- New: func() interface{} {
- return &sliceArrayEncoder{elems: make([]interface{}, 0, 2)}
- },
- }
- func getSliceEncoder() *sliceArrayEncoder {
- return _sliceEncoderPool.Get().(*sliceArrayEncoder)
- }
- func putSliceEncoder(e *sliceArrayEncoder) {
- e.elems = e.elems[:0]
- _sliceEncoderPool.Put(e)
- }
- type consoleEncoder struct {
- *jsonEncoder
- }
- // NewConsoleEncoder creates an encoder whose output is designed for human -
- // rather than machine - consumption. It serializes the core log entry data
- // (message, level, timestamp, etc.) in a plain-text format and leaves the
- // structured context as JSON.
- //
- // Note that although the console encoder doesn't use the keys specified in the
- // encoder configuration, it will omit any element whose key is set to the empty
- // string.
- func NewConsoleEncoder(cfg EncoderConfig) Encoder {
- return consoleEncoder{newJSONEncoder(cfg, true)}
- }
- func (c consoleEncoder) Clone() Encoder {
- return consoleEncoder{c.jsonEncoder.Clone().(*jsonEncoder)}
- }
- func (c consoleEncoder) EncodeEntry(ent Entry, fields []Field) (*buffer.Buffer, error) {
- line := bufferpool.Get()
- // We don't want the entry's metadata to be quoted and escaped (if it's
- // encoded as strings), which means that we can't use the JSON encoder. The
- // simplest option is to use the memory encoder and fmt.Fprint.
- //
- // If this ever becomes a performance bottleneck, we can implement
- // ArrayEncoder for our plain-text format.
- arr := getSliceEncoder()
- if c.TimeKey != "" && c.EncodeTime != nil {
- c.EncodeTime(ent.Time, arr)
- }
- if c.LevelKey != "" && c.EncodeLevel != nil {
- c.EncodeLevel(ent.Level, arr)
- }
- if ent.LoggerName != "" && c.NameKey != "" {
- nameEncoder := c.EncodeName
- if nameEncoder == nil {
- // Fall back to FullNameEncoder for backward compatibility.
- nameEncoder = FullNameEncoder
- }
- nameEncoder(ent.LoggerName, arr)
- }
- if ent.Caller.Defined && c.CallerKey != "" && c.EncodeCaller != nil {
- c.EncodeCaller(ent.Caller, arr)
- }
- for i := range arr.elems {
- if i > 0 {
- line.AppendByte('\t')
- }
- fmt.Fprint(line, arr.elems[i])
- }
- putSliceEncoder(arr)
- // Add the message itself.
- if c.MessageKey != "" {
- c.addTabIfNecessary(line)
- line.AppendString(ent.Message)
- }
- // Add any structured context.
- c.writeContext(line, fields)
- // If there's no stacktrace key, honor that; this allows users to force
- // single-line output.
- if ent.Stack != "" && c.StacktraceKey != "" {
- line.AppendByte('\n')
- line.AppendString(ent.Stack)
- }
- if c.LineEnding != "" {
- line.AppendString(c.LineEnding)
- } else {
- line.AppendString(DefaultLineEnding)
- }
- return line, nil
- }
- func (c consoleEncoder) writeContext(line *buffer.Buffer, extra []Field) {
- context := c.jsonEncoder.Clone().(*jsonEncoder)
- defer context.buf.Free()
- addFields(context, extra)
- context.closeOpenNamespaces()
- if context.buf.Len() == 0 {
- return
- }
- c.addTabIfNecessary(line)
- line.AppendByte('{')
- line.Write(context.buf.Bytes())
- line.AppendByte('}')
- }
- func (c consoleEncoder) addTabIfNecessary(line *buffer.Buffer) {
- if line.Len() > 0 {
- line.AppendByte('\t')
- }
- }
|