sentry-go icon indicating copy to clipboard operation
sentry-go copied to clipboard

Add ability to add custom stacktraces

Open Mokto opened this issue 4 years ago • 13 comments

Hi,

Summary

Add ability to add custom stacktraces to the ones that sentry-go is finding automatically

Motivation

I'm using github.com/ztrue/tracerr that contains all my traces when anything goes wrong.

I'd like to add that information to Sentry, as a stacktrace. The information is not as accurate as the one from tracerr.

I'm currently pushing it as breadcrumbs, which is definitely not ideal (especially since we can't "clear" breadcrumbs)

Thanks!

PS : it might be out of scope, I might misunderstand something about the plugin. If so, I'm sorry :)

Mokto avatar Jun 23 '20 09:06 Mokto

This is a valid request and something we intend to support.

I have a WIP branch to rework the way how stack traces are extracted and it should make room for extraction from custom error types.

I'm currently pushing it as breadcrumbs, which is definitely not ideal (especially since we can't "clear" breadcrumbs)

@Mokto, doesn't Scope.ClearBreadcrumbs work for you?

rhcarvalho avatar Jul 21 '20 12:07 rhcarvalho

It should work indeed ;) I will try soon.

Thanks!

Mokto avatar Jul 21 '20 16:07 Mokto

This is important for us. We're capturing stacktraces and annotating them with meta (breadcrumbs) as we move up the stack, but aren't reporting until we get back up to a root level handler. In raven-go, we have a simple conversion function that works great.

// sentryStacktrace converts our stack representation to Sentry's
func (err *Err) sentryStacktrace() *sentry.Stacktrace {
	frames := make([]*sentry.StacktraceFrame, 0, len(err.frames))
	for i := len(err.frames) - 1; i >= 0; i-- {
		f := err.frames[i]
		frames = append(frames, &sentry.StacktraceFrame{
			Filename:     f.file,
			Function:     f.fn,
			Lineno:       f.line,
			AbsolutePath: f.path,
			InApp:        f.class == classApp,
		})
	}
	return &sentry.Stacktrace{
		Frames: frames,
	}
}

What I can't do today is annotate those frames with their "breadcrumb" data, so that would be very nice. At the end of the day, we're wrapping our errors and just want to convert those and send them to Sentry without a ton of SDK magic. Is that in scope for this SDK or should we look at just using the api directly?

derekperkins avatar Oct 31 '20 16:10 derekperkins

I found that I can skip all the magic by just assembling the *sentry.Event myself, including the stacktrace, which has a spot for variables without using breadcrumbs. It's working great for us now!

	return &sentry.Event{
		Extra:   err.sentryExtra(),
		Level:   err.sentryLevel(),
		Tags:    err.sentryTags(c),
		Message: msg,
		User: sentry.User{
			ID: strconv.Itoa(ctx.UserID(c)),
		},
		Request: req,
		Exception: []sentry.Exception{{
			Value:      err.rootErr.Error(),
			Stacktrace: err.sentryStacktrace(),
		}},
	}

derekperkins avatar Nov 11 '20 19:11 derekperkins

Hi @derekperkins!

From your description in https://github.com/getsentry/sentry-go/issues/253#issuecomment-719957140, I wonder if you considered using BeforeSend or an EventProcessor?

BeforeSend let's you mutate error events before they are sent to Sentry and you should have all info there.

rhcarvalho avatar Nov 13 '20 10:11 rhcarvalho

I really would like to see this implemented. I saw https://github.com/getsentry/sentry-go/pull/310 and I understand why it's not suitable.

I can suggest this, add a function:

func RegisterStackTraceExtractor(f func(error) *StackTrace)

It will add the extractor to a slice. When we want to extract, we iterate over the list of extractor. The first non-nil returned stack trace is used.

By default, Sentry could provide extractors for the most popular libraries.

We could iterate the slice in reverse order, so we give more priority to the extractor registered by the users.

WDYT ?

pierrre avatar Feb 24 '21 16:02 pierrre

@rhcarvalho I just now saw your question. We aren't using Sentry itself to create events, so neither of those options would be useful. We just needed a way to convert our own internal error representation, with associated stacktrace and context vars, to a Stackdriver event, and once I figured out the data model, it worked perfectly, and I submitted a small PR to make it more obvious how the Go fields translate to the Sentry UI https://github.com/getsentry/sentry-go/pull/325

derekperkins avatar Feb 24 '21 21:02 derekperkins

Hello WDYT about my proposal ? https://github.com/getsentry/sentry-go/issues/253#issuecomment-785193900

pierrre avatar Mar 02 '21 08:03 pierrre

Hello ! I would like to be able to use the stack traces from my own error library https://github.com/pierrre/errors Currently in sentry-go it's not possible to easily extract the stack traces from an unsupported third party error library.

I have several options:

  • Improve sentry-go and add support for custom stack trace (large change)
  • Add support for my library in sentry-go (it's a 1 line change, similar to the code that supports the other libraries, but I'm not sure you will accept it)
  • Try to change my library to "look similar" to other error libraries, so sentry-go will be able to extract the stack traces, without any change (I would like to do that, but I'm not sure it's possible)

Here is why I think the 3rd option is not doable:

  • My error type has this method func (err *stack) StackFrames() *runtime.Frames https://github.com/pierrre/errors/blob/17dee35c761a46ea76a0ec550cd5b90d59252b7c/stack.go#L57 , so it will match this condition https://github.com/getsentry/sentry-go/blob/master/stacktrace.go#L79 , but the *runtime.Frames type is not supported by sentry-go
  • I could add support for *runtime.Frames, but that would be costly: convert a []uintptr to *runtime.Frames, iterate over the frames, extract the []uintptr, which is then converted to a *runtime.Frames again
  • The problem is that my error type shares the same method name StackFrames, but I would like to avoid changing it, because "StackFrames" describes correctly what it returns: a *runtime.Frames

Here's what I'm planning to do:

  • add another method StackPCs() []uintptr on my error type
  • update this code https://github.com/getsentry/sentry-go/blob/2503eee7cb11316861b52c5c68c6f364092c5d78/stacktrace.go#L75-L88 and handle the method name StackPCs first

WDYT ?

pierrre avatar Oct 19 '22 13:10 pierrre

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

github-actions[bot] avatar Dec 07 '22 09:12 github-actions[bot]

not fixed

pierrre avatar Dec 07 '22 10:12 pierrre

Bumping this to ask whether Sentry would consider exporting an interface we could wrap errors in that records Stacktrace at the source of the error, much like Rollbar's Go SDK does?

I saw a TODO comment in stacktrace.go to this effect but it seems like nobody got around to it. Happy to take a pass!

the-jackalope avatar Jun 27 '23 19:06 the-jackalope

PRs welcome 🙂

cleptric avatar Jun 27 '23 19:06 cleptric