github.com/mailgun/holster/v4@v4.20.0/errors/context_map.go (about) 1 package errors 2 3 import ( 4 "bytes" 5 "fmt" 6 "io" 7 8 "github.com/mailgun/holster/v4/callstack" 9 pkgerrors "github.com/pkg/errors" //nolint:gomodguard // Legacy code requires deprecated package. 10 ) 11 12 // Implements the `error` `causer` and `Contexter` interfaces 13 type withContext struct { 14 context WithContext 15 msg string 16 cause error 17 stack *callstack.CallStack 18 } 19 20 func (c *withContext) Cause() error { 21 return c.cause 22 } 23 24 func (c *withContext) Error() string { 25 if c.msg == "" { 26 return c.cause.Error() 27 } 28 return c.msg + ": " + c.cause.Error() 29 } 30 31 func (c *withContext) StackTrace() pkgerrors.StackTrace { 32 if child, ok := c.cause.(callstack.HasStackTrace); ok { 33 return child.StackTrace() 34 } 35 return c.stack.StackTrace() 36 } 37 38 func (c *withContext) Context() map[string]interface{} { 39 result := make(map[string]interface{}, len(c.context)) 40 for key, value := range c.context { 41 result[key] = value 42 } 43 44 // downstream context values have precedence as they are closer to the cause 45 if child, ok := c.cause.(HasContext); ok { 46 downstream := child.Context() 47 if downstream == nil { 48 return result 49 } 50 51 for key, value := range downstream { 52 result[key] = value 53 } 54 } 55 return result 56 } 57 58 func (c *withContext) Format(s fmt.State, verb rune) { 59 switch verb { 60 case 'v': 61 _, _ = fmt.Fprintf(s, "%s: %+v (%s)", c.msg, c.Cause(), c.FormatFields()) 62 case 's', 'q': 63 _, _ = io.WriteString(s, c.Error()) 64 } 65 } 66 67 func (c *withContext) FormatFields() string { 68 var buf bytes.Buffer 69 var count int 70 71 for key, value := range c.context { 72 if count > 0 { 73 buf.WriteString(", ") 74 } 75 buf.WriteString(fmt.Sprintf("%+v=%+v", key, value)) 76 count++ 77 } 78 return buf.String() 79 } 80 81 func (c *withContext) Unwrap() error { 82 return c.cause 83 }