// Licensed to Elasticsearch B.V. under one or more contributor // license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright // ownership. Elasticsearch B.V. licenses this file to you under // the Apache License, Version 2.0 (the "License"); you may // not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. package internal import ( "fmt" "sync" "github.com/pkg/errors" "go.uber.org/zap/zapcore" ) type ecsError struct { error } func NewError(err error) zapcore.ObjectMarshaler { return ecsError{err} } func (err ecsError) MarshalLogObject(enc zapcore.ObjectEncoder) error { enc.AddString("message", err.Error()) if e, ok := err.error.(stackTracer); ok { enc.AddString("stack_trace", fmt.Sprintf("%+v", e.StackTrace())) } // TODO(simitt): support for improved error handling // https://github.com/elastic/ecs-logging-go-zap/issues/8 if e, ok := err.error.(errorGroup); ok { if errorCause := e.Errors(); len(errorCause) > 0 { return enc.AddArray("cause", errArray(errorCause)) } } return nil } // interface used by github.com/pkg/errors type stackTracer interface { StackTrace() errors.StackTrace } // *** code below this line is mostly copied from github.com/zapcore/core.go // and is subject to the license below*** // Copyright (c) 2017 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. type errorGroup interface { // Provides read-only access to the underlying list of errors, preferably // without causing any allocs. Errors() []error } // Note that errArry and errArrayElem are very similar to the version // implemented in the top-level error.go file. We can't re-use this because // that would require exporting errArray as part of the zapcore API. // Encodes a list of errors using the standard error encoding logic. type errArray []error func (errs errArray) MarshalLogArray(arr zapcore.ArrayEncoder) error { for i := range errs { if errs[i] == nil { continue } el := newErrArrayElem(errs[i]) arr.AppendObject(el) el.Free() } return nil } var _errArrayElemPool = sync.Pool{New: func() interface{} { return &errArrayElem{} }} // Encodes any error into a {"error": ...} re-using the same errors logic. // // May be passed in place of an array to build a single-element array. type errArrayElem struct{ err error } func newErrArrayElem(err error) *errArrayElem { e := _errArrayElemPool.Get().(*errArrayElem) e.err = err return e } func (e *errArrayElem) MarshalLogArray(arr zapcore.ArrayEncoder) error { return arr.AppendObject(e) } func (e *errArrayElem) MarshalLogObject(enc zapcore.ObjectEncoder) error { return ecsError{e.err}.MarshalLogObject(enc) } func (e *errArrayElem) Free() { e.err = nil _errArrayElemPool.Put(e) }