66package errortrace
77
88import (
9- "bytes"
109 "errors"
1110 "fmt"
12- "runtime"
13- "strconv"
1411 "strings"
1512 "time"
1613
14+ "github.com/DataDog/dd-trace-go/v2/internal/stacktrace"
1715 "github.com/DataDog/dd-trace-go/v2/internal/telemetry"
1816)
1917
2018// TracerError is an error type that holds stackframes from when the error was thrown.
2119// It can be used interchangeably with the built-in Go error type.
2220type TracerError struct {
23- stackFrames * runtime.Frames
24- inner error
25- stack * bytes.Buffer
26- }
21+ rawStack stacktrace.RawStackTrace
2722
28- // defaultStackLength specifies the default maximum size of a stack trace.
29- const defaultStackLength = 32
23+ inner error
24+ }
3025
3126func (err * TracerError ) Error () string {
3227 return err .inner .Error ()
@@ -39,23 +34,20 @@ func New(text string) *TracerError {
3934
4035// Wrap takes in an error and records the stack trace at the moment that it was thrown.
4136func Wrap (err error ) * TracerError {
42- return WrapN (err , 0 , 1 )
37+ return WrapN (err , 1 )
4338}
4439
4540// WrapN takes in an error and records the stack trace at the moment that it was thrown.
46- // It will capture a maximum of `n` entries, skipping the first `skip` entries .
47- // If n is 0, it will capture up to 32 entries instead .
48- func WrapN (err error , n uint , skip uint ) * TracerError {
41+ // Note: The n parameter is ignored; internal/stacktrace uses its own default depth .
42+ // The skip parameter specifies how many stack frames to skip before capturing .
43+ func WrapN (err error , skip uint ) * TracerError {
4944 if err == nil {
5045 return nil
5146 }
5247 var e * TracerError
5348 if errors .As (err , & e ) {
5449 return e
5550 }
56- if n <= 0 {
57- n = defaultStackLength
58- }
5951
6052 telemetry .Count (telemetry .NamespaceTracers , "errorstack.source" , []string {"source:TracerError" }).Submit (1 )
6153 now := time .Now ()
@@ -64,53 +56,24 @@ func WrapN(err error, n uint, skip uint) *TracerError {
6456 telemetry .Distribution (telemetry .NamespaceTracers , "errorstack.duration" , []string {"source:TracerError" }).Submit (dur )
6557 }()
6658
67- pcs := make ([]uintptr , n )
68- var stackFrames * runtime.Frames
69- // +2 to exclude runtime.Callers and Wrap
70- numFrames := runtime .Callers (2 + int (skip ), pcs )
71- if numFrames == 0 {
72- stackFrames = nil
73- } else {
74- stackFrames = runtime .CallersFrames (pcs [:numFrames ])
75- }
59+ // Use SkipAndCaptureUnfiltered to capture all frames including internal DD frames.
60+ // +4 to account for: runtime.Callers, iterator, SkipAndCaptureUnfiltered, and this WrapN function
61+ stack := stacktrace .CaptureRaw (int (skip ) + 2 )
7662
7763 tracerErr := & TracerError {
78- stackFrames : stackFrames ,
79- inner : err ,
64+ rawStack : stack ,
65+ inner : err ,
8066 }
8167 return tracerErr
8268}
8369
8470// Format returns a string representation of the stack trace.
71+ // Uses the centralized internal/stacktrace formatting.
8572func (err * TracerError ) Format () string {
86- if err == nil || err . stackFrames == nil {
73+ if err == nil {
8774 return ""
8875 }
89- if err .stack != nil {
90- return err .stack .String ()
91- }
92-
93- out := bytes.Buffer {}
94- for i := 0 ; ; i ++ {
95- frame , more := err .stackFrames .Next ()
96- if i != 0 {
97- out .WriteByte ('\n' )
98- }
99- out .WriteString (frame .Function )
100- out .WriteByte ('\n' )
101- out .WriteByte ('\t' )
102- out .WriteString (frame .File )
103- out .WriteByte (':' )
104- out .WriteString (strconv .Itoa (frame .Line ))
105- if ! more {
106- break
107- }
108- }
109- // CallersFrames returns an iterator that is consumed as we read it. In order to
110- // allow calling Format() multiple times, we save the result into err.stack, which can be
111- // returned in future calls
112- err .stack = & out
113- return out .String ()
76+ return stacktrace .Format (err .rawStack .Symbolicate ())
11477}
11578
11679// Errorf serves the same purpose as fmt.Errorf, but returns a TracerError
0 commit comments