Files
insights-go/error_tracking_stack_trace.go
T
Manoel Aranda NetoandGitHub 920035f38a docs: document public APIs and hide testing-only flag definitions method (#208)
* docs: add public API Go doc comments

* refactor: hide client feature flag definitions API
2026-05-27 17:48:42 +02:00

84 lines
2.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package posthog
import (
"fmt"
"path/filepath"
"runtime"
"strings"
)
// InAppDecider reports whether a stack frame should be considered “in-app”
// (i.e., part of the calling application’s own code) as opposed to external
// dependencies, standard library, or tooling internals. The UI can use this
// signal to visually emphasize frames that are likely actionable.
type InAppDecider func(frame runtime.Frame) bool
// SimpleInAppDecider is a basic InAppDecider that classifies frames by file path.
// It excludes vendored modules, module cache paths, and Go toolchain paths.
func SimpleInAppDecider(frame runtime.Frame) bool {
f := frame.File
sep := string(filepath.Separator)
if strings.Contains(f, "pkg/mod/golang.org/toolchain") ||
strings.Contains(f, fmt.Sprintf("%[1]svendor%[1]s", sep)) ||
strings.Contains(f, fmt.Sprintf("%[1]spkg%[1]smod%[1]s", sep)) {
return false
}
return true
}
// StackTraceExtractor produces a stack trace for the current goroutine to
// enrich captured exceptions with call-site context.
type StackTraceExtractor interface {
// GetStackTrace returns a PostHog-compatible stack trace.
//
// The skip parameter controls how many leading frames to omit before
// recording. Use it to drop extractor/logging internals and start at the
// application call site. For example, a skip of 3–5 is typically enough to
// hide wrapper layers when called from a slog handler.
GetStackTrace(skip int) *ExceptionStacktrace
}
// DefaultStackTraceExtractor is provided by default as a sane / simple implementation
// of a StackTraceExtractor. It should be enough for most use cases, however, you're free to
// create your own implementation if you require more flexibility.
type DefaultStackTraceExtractor struct {
// InAppDecider decides whether each runtime frame is application code.
// Set it to SimpleInAppDecider or another non-nil function before use.
InAppDecider InAppDecider
}
// GetStackTrace captures the current goroutine stack and converts it to an ExceptionStacktrace.
// The skip parameter omits leading runtime.Callers frames before conversion.
func (d DefaultStackTraceExtractor) GetStackTrace(skip int) *ExceptionStacktrace {
pcs := make([]uintptr, 64)
stackCallCount := runtime.Callers(skip, pcs)
frames := runtime.CallersFrames(pcs[:stackCallCount])
traces := make([]StackFrame, 0, stackCallCount)
for {
frame, hasMore := frames.Next()
if frame == *new(runtime.Frame) {
break
}
traces = append(traces, StackFrame{
Filename: frame.File,
LineNo: frame.Line,
Function: frame.Function,
InApp: d.InAppDecider(frame),
Synthetic: false,
Platform: "go",
})
if !hasMore {
break
}
}
return &ExceptionStacktrace{
Type: "raw",
Frames: traces,
}
}