github.com/matrixorigin/matrixone@v1.2.0/pkg/util/errutil/context.go (about) 1 // Copyright 2022 Matrix Origin 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package errutil 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/cockroachdb/errors/errbase" 22 23 "github.com/matrixorigin/matrixone/pkg/util/stack" 24 "github.com/matrixorigin/matrixone/pkg/util/trace" 25 ) 26 27 // WithContext annotates err with a stack info and a context, which should contain span info. 28 // At the mean time, it will call ReportError to store error info 29 // If err is nil, WithContext returns nil. 30 func WithContext(ctx context.Context, err error) error { 31 return WithContextWithDepth(ctx, err, 1) 32 } 33 34 func WithContextWithDepth(ctx context.Context, err error, depth int) error { 35 if err == nil { 36 return nil 37 } 38 if NoReportFromContext(ctx) { 39 return nil 40 } 41 if _, ok := err.(StackTracer); !ok { 42 err = &withStack{cause: err, Stack: stack.Callers(depth + 1)} 43 } 44 // check SpanContext 45 // if exist NEED a copy for SpanContext, prevent DATA RACE between 'span.SpanContext()' and 'sc.Reset()' 46 span := trace.SpanFromContext(ctx) 47 if sc := span.SpanContext(); !sc.IsEmpty() { 48 newSC := sc.Clone() 49 ctx = trace.ContextWithSpanContext(context.Background(), newSC) 50 } 51 err = &withContext{cause: err, ctx: ctx} 52 GetReportErrorFunc()(ctx, err, depth+1) 53 return err 54 } 55 56 // ContextTracer retrieves the context.Context 57 type ContextTracer interface { 58 Context() context.Context 59 } 60 61 func GetContextTracer(inErr error) ContextTracer { 62 var stacked ContextTracer 63 WalkDeep(inErr, func(err error) bool { 64 if contextTracer, ok := err.(ContextTracer); ok { 65 stacked = contextTracer 66 return true 67 } 68 return false 69 }) 70 return stacked 71 } 72 73 func HasContext(err error) bool { 74 return GetContextTracer(err) != nil 75 } 76 77 var _ error = (*withContext)(nil) 78 var _ Wrapper = (*withContext)(nil) 79 var _ ContextTracer = (*withContext)(nil) 80 var _ fmt.Formatter = (*withContext)(nil) 81 82 type withContext struct { 83 cause error 84 85 ctx context.Context 86 } 87 88 func (w *withContext) Error() string { return w.cause.Error() } 89 func (w *withContext) Cause() error { return w.cause } 90 func (w *withContext) Unwrap() error { return w.cause } 91 func (w *withContext) Context() context.Context { return w.ctx } 92 func (w *withContext) Format(s fmt.State, verb rune) { errbase.FormatError(w, s, verb) }