...

Source file src/go.uber.org/zap/zapcore/field.go

Documentation: go.uber.org/zap/zapcore

     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 zapcore
    22  
    23  import (
    24  	"bytes"
    25  	"fmt"
    26  	"math"
    27  	"reflect"
    28  	"time"
    29  )
    30  
    31  // A FieldType indicates which member of the Field union struct should be used
    32  // and how it should be serialized.
    33  type FieldType uint8
    34  
    35  const (
    36  	// UnknownType is the default field type. Attempting to add it to an encoder will panic.
    37  	UnknownType FieldType = iota
    38  	// ArrayMarshalerType indicates that the field carries an ArrayMarshaler.
    39  	ArrayMarshalerType
    40  	// ObjectMarshalerType indicates that the field carries an ObjectMarshaler.
    41  	ObjectMarshalerType
    42  	// BinaryType indicates that the field carries an opaque binary blob.
    43  	BinaryType
    44  	// BoolType indicates that the field carries a bool.
    45  	BoolType
    46  	// ByteStringType indicates that the field carries UTF-8 encoded bytes.
    47  	ByteStringType
    48  	// Complex128Type indicates that the field carries a complex128.
    49  	Complex128Type
    50  	// Complex64Type indicates that the field carries a complex64.
    51  	Complex64Type
    52  	// DurationType indicates that the field carries a time.Duration.
    53  	DurationType
    54  	// Float64Type indicates that the field carries a float64.
    55  	Float64Type
    56  	// Float32Type indicates that the field carries a float32.
    57  	Float32Type
    58  	// Int64Type indicates that the field carries an int64.
    59  	Int64Type
    60  	// Int32Type indicates that the field carries an int32.
    61  	Int32Type
    62  	// Int16Type indicates that the field carries an int16.
    63  	Int16Type
    64  	// Int8Type indicates that the field carries an int8.
    65  	Int8Type
    66  	// StringType indicates that the field carries a string.
    67  	StringType
    68  	// TimeType indicates that the field carries a time.Time that is
    69  	// representable by a UnixNano() stored as an int64.
    70  	TimeType
    71  	// TimeFullType indicates that the field carries a time.Time stored as-is.
    72  	TimeFullType
    73  	// Uint64Type indicates that the field carries a uint64.
    74  	Uint64Type
    75  	// Uint32Type indicates that the field carries a uint32.
    76  	Uint32Type
    77  	// Uint16Type indicates that the field carries a uint16.
    78  	Uint16Type
    79  	// Uint8Type indicates that the field carries a uint8.
    80  	Uint8Type
    81  	// UintptrType indicates that the field carries a uintptr.
    82  	UintptrType
    83  	// ReflectType indicates that the field carries an interface{}, which should
    84  	// be serialized using reflection.
    85  	ReflectType
    86  	// NamespaceType signals the beginning of an isolated namespace. All
    87  	// subsequent fields should be added to the new namespace.
    88  	NamespaceType
    89  	// StringerType indicates that the field carries a fmt.Stringer.
    90  	StringerType
    91  	// ErrorType indicates that the field carries an error.
    92  	ErrorType
    93  	// SkipType indicates that the field is a no-op.
    94  	SkipType
    95  
    96  	// InlineMarshalerType indicates that the field carries an ObjectMarshaler
    97  	// that should be inlined.
    98  	InlineMarshalerType
    99  )
   100  
   101  // A Field is a marshaling operation used to add a key-value pair to a logger's
   102  // context. Most fields are lazily marshaled, so it's inexpensive to add fields
   103  // to disabled debug-level log statements.
   104  type Field struct {
   105  	Key       string
   106  	Type      FieldType
   107  	Integer   int64
   108  	String    string
   109  	Interface interface{}
   110  }
   111  
   112  // AddTo exports a field through the ObjectEncoder interface. It's primarily
   113  // useful to library authors, and shouldn't be necessary in most applications.
   114  func (f Field) AddTo(enc ObjectEncoder) {
   115  	var err error
   116  
   117  	switch f.Type {
   118  	case ArrayMarshalerType:
   119  		err = enc.AddArray(f.Key, f.Interface.(ArrayMarshaler))
   120  	case ObjectMarshalerType:
   121  		err = enc.AddObject(f.Key, f.Interface.(ObjectMarshaler))
   122  	case InlineMarshalerType:
   123  		err = f.Interface.(ObjectMarshaler).MarshalLogObject(enc)
   124  	case BinaryType:
   125  		enc.AddBinary(f.Key, f.Interface.([]byte))
   126  	case BoolType:
   127  		enc.AddBool(f.Key, f.Integer == 1)
   128  	case ByteStringType:
   129  		enc.AddByteString(f.Key, f.Interface.([]byte))
   130  	case Complex128Type:
   131  		enc.AddComplex128(f.Key, f.Interface.(complex128))
   132  	case Complex64Type:
   133  		enc.AddComplex64(f.Key, f.Interface.(complex64))
   134  	case DurationType:
   135  		enc.AddDuration(f.Key, time.Duration(f.Integer))
   136  	case Float64Type:
   137  		enc.AddFloat64(f.Key, math.Float64frombits(uint64(f.Integer)))
   138  	case Float32Type:
   139  		enc.AddFloat32(f.Key, math.Float32frombits(uint32(f.Integer)))
   140  	case Int64Type:
   141  		enc.AddInt64(f.Key, f.Integer)
   142  	case Int32Type:
   143  		enc.AddInt32(f.Key, int32(f.Integer))
   144  	case Int16Type:
   145  		enc.AddInt16(f.Key, int16(f.Integer))
   146  	case Int8Type:
   147  		enc.AddInt8(f.Key, int8(f.Integer))
   148  	case StringType:
   149  		enc.AddString(f.Key, f.String)
   150  	case TimeType:
   151  		if f.Interface != nil {
   152  			enc.AddTime(f.Key, time.Unix(0, f.Integer).In(f.Interface.(*time.Location)))
   153  		} else {
   154  			// Fall back to UTC if location is nil.
   155  			enc.AddTime(f.Key, time.Unix(0, f.Integer))
   156  		}
   157  	case TimeFullType:
   158  		enc.AddTime(f.Key, f.Interface.(time.Time))
   159  	case Uint64Type:
   160  		enc.AddUint64(f.Key, uint64(f.Integer))
   161  	case Uint32Type:
   162  		enc.AddUint32(f.Key, uint32(f.Integer))
   163  	case Uint16Type:
   164  		enc.AddUint16(f.Key, uint16(f.Integer))
   165  	case Uint8Type:
   166  		enc.AddUint8(f.Key, uint8(f.Integer))
   167  	case UintptrType:
   168  		enc.AddUintptr(f.Key, uintptr(f.Integer))
   169  	case ReflectType:
   170  		err = enc.AddReflected(f.Key, f.Interface)
   171  	case NamespaceType:
   172  		enc.OpenNamespace(f.Key)
   173  	case StringerType:
   174  		err = encodeStringer(f.Key, f.Interface, enc)
   175  	case ErrorType:
   176  		err = encodeError(f.Key, f.Interface.(error), enc)
   177  	case SkipType:
   178  		break
   179  	default:
   180  		panic(fmt.Sprintf("unknown field type: %v", f))
   181  	}
   182  
   183  	if err != nil {
   184  		enc.AddString(fmt.Sprintf("%sError", f.Key), err.Error())
   185  	}
   186  }
   187  
   188  // Equals returns whether two fields are equal. For non-primitive types such as
   189  // errors, marshalers, or reflect types, it uses reflect.DeepEqual.
   190  func (f Field) Equals(other Field) bool {
   191  	if f.Type != other.Type {
   192  		return false
   193  	}
   194  	if f.Key != other.Key {
   195  		return false
   196  	}
   197  
   198  	switch f.Type {
   199  	case BinaryType, ByteStringType:
   200  		return bytes.Equal(f.Interface.([]byte), other.Interface.([]byte))
   201  	case ArrayMarshalerType, ObjectMarshalerType, ErrorType, ReflectType:
   202  		return reflect.DeepEqual(f.Interface, other.Interface)
   203  	default:
   204  		return f == other
   205  	}
   206  }
   207  
   208  func addFields(enc ObjectEncoder, fields []Field) {
   209  	for i := range fields {
   210  		fields[i].AddTo(enc)
   211  	}
   212  }
   213  
   214  func encodeStringer(key string, stringer interface{}, enc ObjectEncoder) (retErr error) {
   215  	// Try to capture panics (from nil references or otherwise) when calling
   216  	// the String() method, similar to https://golang.org/src/fmt/print.go#L540
   217  	defer func() {
   218  		if err := recover(); err != nil {
   219  			// If it's a nil pointer, just say "<nil>". The likeliest causes are a
   220  			// Stringer that fails to guard against nil or a nil pointer for a
   221  			// value receiver, and in either case, "<nil>" is a nice result.
   222  			if v := reflect.ValueOf(stringer); v.Kind() == reflect.Ptr && v.IsNil() {
   223  				enc.AddString(key, "<nil>")
   224  				return
   225  			}
   226  
   227  			retErr = fmt.Errorf("PANIC=%v", err)
   228  		}
   229  	}()
   230  
   231  	enc.AddString(key, stringer.(fmt.Stringer).String())
   232  	return nil
   233  }
   234  

View as plain text