@@ -16,9 +16,11 @@ type Error struct {
1616 stackTrace * stackTrace
1717 // properties are used both for public properties inherited through "transparent" wrapping
1818 // and for some optional per-instance information like "underlying errors"
19- properties * propertyMap
20- transparent bool
21- hasUnderlying bool
19+ properties * propertyMap
20+
21+ transparent bool
22+ hasUnderlying bool
23+ printablePropertyCount uint8
2224}
2325
2426var _ fmt.Formatter = (* Error )(nil )
@@ -31,6 +33,9 @@ var _ fmt.Formatter = (*Error)(nil)
3133func (e * Error ) WithProperty (key Property , value interface {}) * Error {
3234 errorCopy := * e
3335 errorCopy .properties = errorCopy .properties .with (key , value )
36+ if key .printable && errorCopy .printablePropertyCount < 255 {
37+ errorCopy .printablePropertyCount ++
38+ }
3439 return & errorCopy
3540}
3641
@@ -205,6 +210,25 @@ func (e *Error) underlyingInfo() string {
205210 return fmt .Sprintf ("(hidden: %s)" , joinStringsIfNonEmpty (", " , infos ... ))
206211}
207212
213+ func (e * Error ) messageFromProperties () string {
214+ if e .printablePropertyCount == 0 {
215+ return ""
216+ }
217+ uniq := make (map [Property ]struct {}, e .printablePropertyCount )
218+ strs := make ([]string , 0 , e .printablePropertyCount )
219+ for m := e .properties ; m != nil ; m = m .next {
220+ if ! m .p .printable {
221+ continue
222+ }
223+ if _ , ok := uniq [m .p ]; ok {
224+ continue
225+ }
226+ uniq [m .p ] = struct {}{}
227+ strs = append (strs , fmt .Sprintf ("%s: %v" , m .p .label , m .value ))
228+ }
229+ return "{" + strings .Join (strs , ", " ) + "}"
230+ }
231+
208232func (e * Error ) underlying () []error {
209233 if ! e .hasUnderlying {
210234 return nil
@@ -216,21 +240,35 @@ func (e *Error) underlying() []error {
216240}
217241
218242func (e * Error ) messageText () string {
219- if e .Cause () == nil {
220- return e .message
243+ message := joinStringsIfNonEmpty (" " , e .message , e .messageFromProperties ())
244+ if cause := e .Cause (); cause != nil {
245+ return joinStringsIfNonEmpty (", cause: " , message , cause .Error ())
221246 }
222-
223- underlyingFullMessage := e .Cause ().Error ()
224- return joinStringsIfNonEmpty (", cause: " , e .message , underlyingFullMessage )
247+ return message
225248}
226249
227250func joinStringsIfNonEmpty (delimiter string , parts ... string ) string {
228- filteredParts := make ([]string , 0 , len (parts ))
229- for _ , part := range parts {
230- if len (part ) > 0 {
231- filteredParts = append (filteredParts , part )
251+ switch len (parts ) {
252+ case 0 :
253+ return ""
254+ case 1 :
255+ return parts [0 ]
256+ case 2 :
257+ if len (parts [0 ]) == 0 {
258+ return parts [1 ]
259+ } else if len (parts [1 ]) == 0 {
260+ return parts [0 ]
261+ } else {
262+ return parts [0 ] + delimiter + parts [1 ]
263+ }
264+ default :
265+ filteredParts := make ([]string , 0 , len (parts ))
266+ for _ , part := range parts {
267+ if len (part ) > 0 {
268+ filteredParts = append (filteredParts , part )
269+ }
232270 }
233- }
234271
235- return strings .Join (filteredParts , delimiter )
272+ return strings .Join (filteredParts , delimiter )
273+ }
236274}
0 commit comments