diff --git a/errors.go b/errors.go index 1231f36..d998251 100644 --- a/errors.go +++ b/errors.go @@ -199,6 +199,15 @@ outer: return buffer.String() } +// MessageChainString returns a formatted string of the full message chain. +// Each message in the chain is joined with " -> ". +func (p *Error) MessageChainString() string { + if p == nil { + return "" + } + return strings.Join(p.MessageChain, " -> ") +} + // VerboseString returns the error message, stack trace and params func (p *Error) VerboseString() string { return fmt.Sprintf("%s\nParams: %+v\n%s", p.Error(), p.Params, p.StackString()) diff --git a/errors_test.go b/errors_test.go index 5d2c230..6a8fe99 100644 --- a/errors_test.go +++ b/errors_test.go @@ -604,6 +604,31 @@ func TestStackStringChasesCausalChain(t *testing.T) { assert.Contains(t, ss, "failyFunction") } +func TestMessageChainString(t *testing.T) { + t.Run("simple chain", func(t *testing.T) { + err := &Error{ + Code: ErrInternalService, + MessageChain: []string{"top-level", "cause"}, + } + out := err.MessageChainString() + assert.Equal(t, "top-level -> cause", out) + }) + + t.Run("single message", func(t *testing.T) { + err := &Error{ + Code: ErrNotFound, + MessageChain: []string{"only one"}, + } + out := err.MessageChainString() + assert.Equal(t, "only one", out) + }) + + t.Run("nil error returns empty string", func(t *testing.T) { + var err *Error + assert.Equal(t, "", err.MessageChainString()) + }) +} + func TestCircularErrorProducesFiniteOutputWithStackFrames(t *testing.T) { orig := failyFunction() err := Augment(orig, "something may be up", nil)