Skip to content

Commit

Permalink
add GetTraces() and slog helper
Browse files Browse the repository at this point in the history
  • Loading branch information
viatoriche committed Sep 23, 2024
1 parent 30050ab commit 165b098
Show file tree
Hide file tree
Showing 6 changed files with 378 additions and 199 deletions.
45 changes: 45 additions & 0 deletions slogex.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package stacktrace

import (
"fmt"
"log/slog"
)

func ErrToSlogAttr(err error, opts ...TracesOpt) slog.Attr {
if err == nil {
return slog.Attr{}
}

st, ok := Unwrap(err)
if !ok {
return slog.String("error", err.Error())
}

if st == nil {
return slog.String("error", "nil stacktrace")
}

tracebacks := st.GetTraces(opts...)

tracebackAttrs := make([]slog.Attr, 0, len(tracebacks))
for traceIndex := range tracebacks {
traceback := tracebacks[traceIndex]
stackAttrs := make([]slog.Attr, 0, len(traceback.Stack))
for stackIndex := range traceback.Stack {
stack := traceback.Stack[stackIndex]
key := fmt.Sprintf("%d", stackIndex)
stackAttr := slog.Group(
key,
slog.String("type", string(stack.Type)),
slog.String("severity", string(stack.Severity)),
slog.String("position", stack.LinePos),
slog.String("message", stack.Message),
)
stackAttrs = append(stackAttrs, stackAttr)
}
tracebackAttr := slog.Group(fmt.Sprintf("%d", traceIndex), "stack", stackAttrs)
tracebackAttrs = append(tracebackAttrs, tracebackAttr)
}

return slog.Group("tracebacks", "traces", tracebackAttrs)
}
123 changes: 0 additions & 123 deletions sprint.go

This file was deleted.

70 changes: 0 additions & 70 deletions sprint_test.go

This file was deleted.

18 changes: 12 additions & 6 deletions stacktrace.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,8 @@ func (st *StackTrace) Header() string {
result := fmt.Sprintf("[%s] %s: %s",
st.Severity,
st.Type,
st.Location,
st.GetLocWithPos(),
)
if st.Position != nil {
result = fmt.Sprintf("%s:%d:%d", result, st.Position.Line, st.Position.Column)
} else {
result = fmt.Sprintf("%s:1", result)
}
return result
}

Expand Down Expand Up @@ -442,6 +437,17 @@ func (st *StackTrace) Clone() *StackTrace {
return &c
}

// GetLocWithPos returns the location with position of the StackTrace.
func (st *StackTrace) GetLocWithPos() string {
result := st.Location
if st.Position != nil {
result = fmt.Sprintf("%s:%d:%d", result, st.Position.Line, st.Position.Column)
} else {
result = fmt.Sprintf("%s:1", result)
}
return result
}

// Position contains the line and column where the error occurred.
type Position struct {
Line int
Expand Down
96 changes: 96 additions & 0 deletions traces.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package stacktrace

type TracesOpt interface {
Apply(o *TracesOptions)
}

type TracesOptions struct {
// EnsureDuplicates ensures that duplicates are not printed
EnsureDuplicates bool
dupLocs map[string]struct{}
}

func NewTracesOptions() *TracesOptions {
opts := &TracesOptions{
EnsureDuplicates: false,
dupLocs: make(map[string]struct{}),
}
return opts
}

type ensureDuplicatesOpt struct{}

func (ensureDuplicatesOpt) Apply(o *TracesOptions) {
o.EnsureDuplicates = true
}

func WithEnsureDuplicates() TracesOpt {
return &ensureDuplicatesOpt{}
}

type Stack struct {
LinePos string
Severity Severity
Message string
Type Type
}

func NewStack() *Stack {
return &Stack{}
}

type Trace struct {
Stack []Stack
}

func NewTrace() *Trace {
return &Trace{Stack: make([]Stack, 0)}
}

func (st *StackTrace) getTraces(opts *TracesOptions) []Trace {
traces := make([]Trace, 0)

tracesWithList := func() []Trace {
for _, elem := range st.List {
elemTraces := elem.getTraces(opts)
traces = append(traces, elemTraces...)
}
return traces
}

trace := NewTrace()
stack := NewStack()
stack.LinePos = st.GetLocWithPos()
stack.Severity = st.Severity
stack.Message = st.FullMessageWithInfo()
stack.Type = st.Type

if _, ok := opts.dupLocs[stack.LinePos]; ok {
return tracesWithList()
}

trace.Stack = append(trace.Stack, *stack)
if st.Wrapped != nil {
wrappedTraces := st.Wrapped.getTraces(opts)
if len(wrappedTraces) == 0 {
return tracesWithList()
}
for i := range wrappedTraces {
trace.Stack = append(trace.Stack, wrappedTraces[i].Stack...)
}
} else if opts.EnsureDuplicates {
opts.dupLocs[stack.LinePos] = struct{}{}
}

traces = append(traces, *trace)

return tracesWithList()
}

func (st *StackTrace) GetTraces(opts ...TracesOpt) []Trace {
o := NewTracesOptions()
for _, opt := range opts {
opt.Apply(o)
}
return st.getTraces(o)
}
Loading

0 comments on commit 165b098

Please sign in to comment.