github.com/cockroachdb/errors@v1.11.1/errutil/utilities.go (about) 1 // Copyright 2019 The Cockroach Authors. 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 12 // implied. See the License for the specific language governing 13 // permissions and limitations under the License. 14 15 package errutil 16 17 import ( 18 "github.com/cockroachdb/errors/join" 19 "github.com/cockroachdb/errors/secondary" 20 "github.com/cockroachdb/errors/withstack" 21 "github.com/cockroachdb/redact" 22 ) 23 24 // New creates an error with a simple error message. 25 // A stack trace is retained. 26 // 27 // Note: the message string is assumed to not contain 28 // PII and is included in Sentry reports. 29 // Use errors.Newf("%s", <unsafestring>) for errors 30 // strings that may contain PII information. 31 // 32 // Detail output: 33 // - message via `Error()` and formatting using `%v`/`%s`/`%q`. 34 // - everything when formatting with `%+v`. 35 // - stack trace and message via `errors.GetSafeDetails()`. 36 // - stack trace and message in Sentry reports. 37 func New(msg string) error { 38 return NewWithDepth(1, msg) 39 } 40 41 // NewWithDepth is like New() except the depth to capture the stack 42 // trace is configurable. 43 // See the doc of `New()` for more details. 44 func NewWithDepth(depth int, msg string) error { 45 err := error(&leafError{redact.Sprint(redact.Safe(msg))}) 46 err = withstack.WithStackDepth(err, 1+depth) 47 return err 48 } 49 50 // Newf creates an error with a formatted error message. 51 // A stack trace is retained. 52 // 53 // Note: the format string is assumed to not contain 54 // PII and is included in Sentry reports. 55 // Use errors.Newf("%s", <unsafestring>) for errors 56 // strings that may contain PII information. 57 // 58 // See the doc of `New()` for more details. 59 func Newf(format string, args ...interface{}) error { 60 return NewWithDepthf(1, format, args...) 61 } 62 63 // NewWithDepthf is like Newf() except the depth to capture the stack 64 // trace is configurable. 65 // See the doc of `New()` for more details. 66 func NewWithDepthf(depth int, format string, args ...interface{}) error { 67 // If there's the verb %w in here, shortcut to fmt.Errorf() 68 // and store the safe details as extra payload. That's 69 // because we don't want to re-implement the error wrapping 70 // logic from 'fmt' in there. 71 var err error 72 var errRefs []error 73 for _, a := range args { 74 if e, ok := a.(error); ok { 75 errRefs = append(errRefs, e) 76 } 77 } 78 redactable, wrappedErr := redact.HelperForErrorf(format, args...) 79 if wrappedErr != nil { 80 err = &withNewMessage{cause: wrappedErr, message: redactable} 81 } else { 82 err = &leafError{redactable} 83 } 84 for _, e := range errRefs { 85 err = secondary.WithSecondaryError(err, e) 86 } 87 err = withstack.WithStackDepth(err, 1+depth) 88 return err 89 } 90 91 // Wrap wraps an error with a message prefix. 92 // A stack trace is retained. 93 // 94 // Note: the prefix string is assumed to not contain 95 // PII and is included in Sentry reports. 96 // Use errors.Wrapf(err, "%s", <unsafestring>) for errors 97 // strings that may contain PII information. 98 // 99 // Detail output: 100 // - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`. 101 // - everything when formatting with `%+v`. 102 // - stack trace and message via `errors.GetSafeDetails()`. 103 // - stack trace and message in Sentry reports. 104 func Wrap(err error, msg string) error { 105 return WrapWithDepth(1, err, msg) 106 } 107 108 // WrapWithDepth is like Wrap except the depth to capture the stack 109 // trace is configurable. 110 // The the doc of `Wrap()` for more details. 111 func WrapWithDepth(depth int, err error, msg string) error { 112 if err == nil { 113 return nil 114 } 115 if msg != "" { 116 err = WithMessage(err, msg) 117 } 118 err = withstack.WithStackDepth(err, depth+1) 119 return err 120 } 121 122 // Wrapf wraps an error with a formatted message prefix. A stack 123 // trace is also retained. If the format is empty, no prefix is added, 124 // but the extra arguments are still processed for reportable strings. 125 // 126 // Note: the format string is assumed to not contain 127 // PII and is included in Sentry reports. 128 // Use errors.Wrapf(err, "%s", <unsafestring>) for errors 129 // strings that may contain PII information. 130 // 131 // Detail output: 132 // - original error message + prefix via `Error()` and formatting using `%v`/`%s`/`%q`. 133 // - everything when formatting with `%+v`. 134 // - stack trace, format, and redacted details via `errors.GetSafeDetails()`. 135 // - stack trace, format, and redacted details in Sentry reports. 136 func Wrapf(err error, format string, args ...interface{}) error { 137 return WrapWithDepthf(1, err, format, args...) 138 } 139 140 // WrapWithDepthf is like Wrapf except the depth to capture the stack 141 // trace is configurable. 142 // The the doc of `Wrapf()` for more details. 143 func WrapWithDepthf(depth int, err error, format string, args ...interface{}) error { 144 if err == nil { 145 return nil 146 } 147 var errRefs []error 148 for _, a := range args { 149 if e, ok := a.(error); ok { 150 errRefs = append(errRefs, e) 151 } 152 } 153 if format != "" || len(args) > 0 { 154 err = WithMessagef(err, format, args...) 155 } 156 for _, e := range errRefs { 157 err = secondary.WithSecondaryError(err, e) 158 } 159 err = withstack.WithStackDepth(err, depth+1) 160 return err 161 } 162 163 // JoinWithDepth constructs a Join error with the provided list of 164 // errors as arguments, and wraps it in a `WithStackDepth` to capture a 165 // stacktrace alongside. 166 func JoinWithDepth(depth int, errs ...error) error { 167 return withstack.WithStackDepth(join.Join(errs...), depth+1) 168 }