error.go raw

   1  // Copyright (c) 2017 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  	"go.uber.org/zap/internal/pool"
  25  	"go.uber.org/zap/zapcore"
  26  )
  27  
  28  var _errArrayElemPool = pool.New(func() *errArrayElem {
  29  	return &errArrayElem{}
  30  })
  31  
  32  // Error is shorthand for the common idiom NamedError("error", err).
  33  func Error(err error) Field {
  34  	return NamedError("error", err)
  35  }
  36  
  37  // NamedError constructs a field that lazily stores err.Error() under the
  38  // provided key. Errors which also implement fmt.Formatter (like those produced
  39  // by github.com/pkg/errors) will also have their verbose representation stored
  40  // under key+"Verbose". If passed a nil error, the field is a no-op.
  41  //
  42  // For the common case in which the key is simply "error", the Error function
  43  // is shorter and less repetitive.
  44  func NamedError(key string, err error) Field {
  45  	if err == nil {
  46  		return Skip()
  47  	}
  48  	return Field{Key: key, Type: zapcore.ErrorType, Interface: err}
  49  }
  50  
  51  type errArray []error
  52  
  53  func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error {
  54  	for i := range errs {
  55  		if errs[i] == nil {
  56  			continue
  57  		}
  58  		// To represent each error as an object with an "error" attribute and
  59  		// potentially an "errorVerbose" attribute, we need to wrap it in a
  60  		// type that implements LogObjectMarshaler. To prevent this from
  61  		// allocating, pool the wrapper type.
  62  		elem := _errArrayElemPool.Get()
  63  		elem.error = errs[i]
  64  		err := arr.AppendObject(elem)
  65  		elem.error = nil
  66  		_errArrayElemPool.Put(elem)
  67  		if err != nil {
  68  			return err
  69  		}
  70  	}
  71  	return nil
  72  }
  73  
  74  type errArrayElem struct {
  75  	error
  76  }
  77  
  78  func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error {
  79  	// Re-use the error field's logic, which supports non-standard error types.
  80  	Error(e.error).AddTo(enc)
  81  	return nil
  82  }
  83