BuildSentryReport builds the components of a sentry report. This can be used instead of ReportError() below to use additional custom conditions in the reporting or add additional reporting tags. The Sentry Event is populated for maximal utility when exploited in the Sentry.io web interface and dat
(err error)
| 98 | // provided by the library, but could impact error types defined by |
| 99 | // 3rd parties. This limitation may be lifted in a later version. |
| 100 | func BuildSentryReport(err error) (event *sentry.Event, extraDetails map[string]interface{}) { |
| 101 | if err == nil { |
| 102 | // No error: do nothing. |
| 103 | return |
| 104 | } |
| 105 | |
| 106 | // First step is to collect the details. |
| 107 | var stacks []*withstack.ReportableStackTrace |
| 108 | var details []errbase.SafeDetailPayload |
| 109 | visitAllMulti(err, func(c error) { |
| 110 | st := withstack.GetReportableStackTrace(c) |
| 111 | stacks = append(stacks, st) |
| 112 | |
| 113 | sd := errbase.GetSafeDetails(c) |
| 114 | details = append(details, sd) |
| 115 | }) |
| 116 | module := string(domains.GetDomain(err)) |
| 117 | |
| 118 | // firstDetailLine is the first detail string encountered. |
| 119 | // This is added as decoration to the first Exception |
| 120 | // payload (either from the error object or synthetic) |
| 121 | // so as to populate the Sentry report title. |
| 122 | var firstDetailLine string |
| 123 | |
| 124 | // longMsgBuf will become the Message field, which contains the full |
| 125 | // structure of the error. |
| 126 | var longMsgBuf strings.Builder |
| 127 | if f, l, _, ok := withstack.GetOneLineSource(err); ok { |
| 128 | fmt.Fprintf(&longMsgBuf, "%s:%d: ", f, l) |
| 129 | } |
| 130 | // Include the verbose error printout, with sensitive bits redacted out. |
| 131 | verboseErr := redact.Sprintf("%+v", err).Redact().StripMarkers() |
| 132 | if verboseErr != redactedMarker { |
| 133 | idx := strings.IndexByte(verboseErr, '\n') |
| 134 | if idx == -1 { |
| 135 | firstDetailLine = verboseErr |
| 136 | } else { |
| 137 | firstDetailLine = verboseErr[:idx] |
| 138 | } |
| 139 | } |
| 140 | fmt.Fprint(&longMsgBuf, verboseErr) |
| 141 | |
| 142 | // sep is used to separate the entries in the longMsgBuf / Message |
| 143 | // payload. |
| 144 | sep := "" |
| 145 | |
| 146 | // extras will become the per-layer "Additional data" fields. |
| 147 | extras := make(map[string]interface{}) |
| 148 | |
| 149 | // extraNum counts the number of "Additional data" payloads and is |
| 150 | // used to generate the cross-reference counters in the Message |
| 151 | // payload. |
| 152 | extraNum := 1 |
| 153 | |
| 154 | // typesBuf will become the payload for the "error types" Additional |
| 155 | // data field. It explains the Go types of the layers in the error |
| 156 | // object. |
| 157 | var typesBuf strings.Builder |
no test coverage detected
searching dependent graphs…