diff --git a/errkit/README.md b/errkit/README.md index 4279e06..8821fc3 100644 --- a/errkit/README.md +++ b/errkit/README.md @@ -47,10 +47,10 @@ with attributes support you can do following err := errkit.New("i/o timeout") // xyz.go -err = errkit.WithAttr(err,slog.Any("resource",domain)) +err = errkit.WithAttr(err, slog.String("resource", domain)) // abc.go -err = errkit.WithAttr(err,slog.Any("action","download")) +err = errkit.WithAttr(err, slog.String("action", "download")) ``` ## Note diff --git a/errkit/errors.go b/errkit/errors.go index 728fcab..e0e7d15 100644 --- a/errkit/errors.go +++ b/errkit/errors.go @@ -293,7 +293,7 @@ func (e *ErrorX) ResetKind() *ErrorX { return e } -// Deprecated: use Attrs instead +// Deprecated: use WithAttr instead // // SetAttr sets additional attributes to a given error // it only adds unique attributes and ignores duplicates @@ -303,6 +303,9 @@ func (e *ErrorX) ResetKind() *ErrorX { // // this is correct (√) // myError.SetAttr(slog.String("address",host)) +// +// Recommended replacement: +// errkit.WithAttr(myError, slog.String("address", host)) func (e *ErrorX) SetAttr(s ...slog.Attr) *ErrorX { e.init() for _, attr := range s { diff --git a/errkit/errors_test.go b/errkit/errors_test.go index a27cb16..0f4132f 100644 --- a/errkit/errors_test.go +++ b/errkit/errors_test.go @@ -10,6 +10,7 @@ import ( "go.uber.org/multierr" stderrors "errors" + "log/slog" ) // what are these tests ? @@ -126,3 +127,41 @@ func TestErrorString(t *testing.T) { x.Error(), ) } + +func TestWithAttr(t *testing.T) { + // Test WithAttr function + originalErr := New("connection failed") + + // Add attributes using WithAttr + err := WithAttr(originalErr, slog.String("resource", "database"), slog.Int("port", 5432)) + + // Verify the error can be unwrapped to ErrorX + var errx *ErrorX + require.True(t, errors.As(err, &errx), "expected to be able to unwrap to ErrorX") + + // Check that attributes were added + attrs := errx.Attrs() + require.Len(t, attrs, 2, "expected 2 attributes") + + // Verify specific attributes + foundResource := false + foundPort := false + for _, attr := range attrs { + if attr.Key == "resource" && attr.Value.String() == "database" { + foundResource = true + } + if attr.Key == "port" && attr.Value.Int64() == 5432 { + foundPort = true + } + } + require.True(t, foundResource, "expected to find resource attribute") + require.True(t, foundPort, "expected to find port attribute") + + // Test that WithAttr works with nil error + nilErr := WithAttr(nil, slog.String("test", "value")) + require.Nil(t, nilErr, "expected nil error to return nil") + + // Test that WithAttr works with empty attrs + emptyErr := WithAttr(originalErr) + require.Equal(t, originalErr, emptyErr, "expected original error when no attrs provided") +} diff --git a/errkit/helpers.go b/errkit/helpers.go index 8bff426..5d69248 100644 --- a/errkit/helpers.go +++ b/errkit/helpers.go @@ -210,6 +210,26 @@ func With(err error, args ...any) error { return x } +// WithAttr adds extra attributes to the error using slog.Attr +// +// err = errkit.WithAttr(err, slog.String("resource", domain)) +// err = errkit.WithAttr(err, slog.Int("port", 80), slog.String("protocol", "tcp")) +func WithAttr(err error, attrs ...slog.Attr) error { + if err == nil { + return nil + } + if len(attrs) == 0 { + return err + } + x := &ErrorX{} + x.init() + parseError(x, err) + for _, attr := range attrs { + x.record.Add(attr) + } + return x +} + // GetAttr returns all attributes of given error if it has any func GetAttr(err error) []slog.Attr { if err == nil {