Skip to content

Commit

Permalink
add a top level Slog function.
Browse files Browse the repository at this point in the history
This if for generating an error.
Wraps is inconvenient if there isn't an existing error to wrap.
  • Loading branch information
Greg Weber committed Jul 1, 2024
1 parent 2f1d848 commit 3a79415
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 6 deletions.
13 changes: 11 additions & 2 deletions structured.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,17 @@ func (se structuredErr) Format(s fmt.State, verb rune) {
}
}

// S=structured
// Accepts as args any valid slog args. These will generate an slog Record
// Slog creates an error that instead of generating a format string generates a structured slog Record.
// Accepts as args any valid slog args.
// Also accepts []slog.Attr as a single argument to avoid having to cast that argument.
// The slog Record can be retrieved with SlogRecord.
// Structured errors are more often created by wrapping existing errors with Wraps.
func Slog(msg string, args ...interface{}) StructuredError {
return Wraps(New(msg), "", args...)
}

// Wraps ends with an "s" to indicate it is Structured.
// Accepts as args any valid slog args. These will generate an slog Record
// Also accepts []slog.Attr as a single argument to avoid having to cast that argument.
func Wraps(err error, msg string, args ...interface{}) StructuredError {
if err == nil {
Expand Down
61 changes: 57 additions & 4 deletions structured_test.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,68 @@
package errors

import (
"bytes"
"context"
"errors"
"log/slog"
"strings"
"testing"
)

func TestStructuredBad(t *testing.T) {
errBad := Slog(
"cause1",
"structured1",
"key", "value",
"int", 1,
)
record := SlogRecord(errBad)
if numAttrs := record.NumAttrs(); numAttrs != 3 {
t.Errorf("expected 3 attributes, got %d for %s", numAttrs, errBad.Error())
}
handler, getBuf := SlogTextBuffer(nil)
if err := handler.Handle(context.Background(), *record); err != nil {
t.Fatalf("error writing out record %+v", err)
}
if !strings.Contains(getBuf(), "!BADKEY") {
t.Errorf("expected BADKEY from bad wrapping")
}
}

func TestStructured(t *testing.T) {
errInner := Slog(
"cause1",
"key", "value",
"int", 1,
)
err := Wraps(
errInner,
"structured2",
"key", "value",
"int", 3,
)

if numAttrs := err.GetSlogRecord().NumAttrs(); numAttrs != 2 {
t.Errorf("expected 2 attributes, got %d for %s", numAttrs, err.Error())
}
record := SlogRecord(err)
if numAttrs := record.NumAttrs(); numAttrs != 4 {
t.Errorf("expected 4 attributes, got %d for %s", numAttrs, err.Error())
}

// Test stack trace
hOpts := slog.HandlerOptions{
AddSource: true,
}
handler, getBuf := SlogTextBuffer(&hOpts)
if err := handler.Handle(context.Background(), *record); err != nil {
t.Fatalf("error writing out record %+v", err)
}
if !strings.Contains(getBuf(), "structured_test.go") {
t.Errorf("expected stack trace with file")
}
}

func TestStructuredWrap(t *testing.T) {
errInner := Wraps(
New("cause1"),
"structured1",
Expand All @@ -35,11 +88,11 @@ func TestStructured(t *testing.T) {
hOpts := slog.HandlerOptions{
AddSource: true,
}
buf := new(bytes.Buffer)
if err := slog.NewTextHandler(buf, &hOpts).Handle(context.Background(), *record); err != nil {
handler, getBuf := SlogTextBuffer(&hOpts)
if err := handler.Handle(context.Background(), *record); err != nil {
t.Fatalf("error writing out record %+v", err)
}
if !strings.Contains(buf.String(), "structured_test.go") {
if !strings.Contains(getBuf(), "structured_test.go") {
t.Errorf("expected stack trace with file")
}
}
Expand Down

0 comments on commit 3a79415

Please sign in to comment.