github.com/oinume/lekcije@v0.0.0-20231017100347-5b4c5eb6ab24/backend/infrastructure/rollbar/repository.go (about)

     1  package rollbar
     2  
     3  import (
     4  	"context"
     5  	"runtime"
     6  
     7  	pkg_errors "github.com/pkg/errors"
     8  	"github.com/rollbar/rollbar-go"
     9  
    10  	"github.com/oinume/lekcije/backend/domain/repository"
    11  	"github.com/oinume/lekcije/backend/errors"
    12  )
    13  
    14  type errorRecorderRepository struct {
    15  	client Client
    16  }
    17  
    18  func NewErrorRecorderRepository(client Client) repository.ErrorRecorder {
    19  	client.SetStackTracer(StackTracer)
    20  	return &errorRecorderRepository{
    21  		client: client,
    22  	}
    23  }
    24  
    25  func (r *errorRecorderRepository) Record(ctx context.Context, err error, userID string) {
    26  	if userID != "" {
    27  		ctx = rollbar.NewPersonContext(ctx, &rollbar.Person{
    28  			Id: userID,
    29  		})
    30  	}
    31  	r.client.ErrorWithStackSkipWithExtrasAndContext(ctx, "error", err, 0, nil)
    32  }
    33  
    34  func StackTracer(err error) ([]runtime.Frame, bool) {
    35  	switch e := err.(type) {
    36  	case *errors.AnnotatedError:
    37  		if !e.OutputStackTrace() {
    38  			return nil, false
    39  		}
    40  		return toFrames(e.StackTrace()), true
    41  	case errors.StackTracer:
    42  		return toFrames(e.StackTrace()), true
    43  	default:
    44  		return nil, false
    45  	}
    46  }
    47  
    48  func toFrames(st pkg_errors.StackTrace) []runtime.Frame {
    49  	frames := make([]runtime.Frame, 0, len(st))
    50  	for _, f := range st {
    51  		pc := uintptr(f)
    52  		fn := runtime.FuncForPC(pc)
    53  		file, line := fn.FileLine(pc)
    54  		frame := runtime.Frame{
    55  			PC:       pc,
    56  			Func:     fn,
    57  			Function: fn.Name(),
    58  			File:     file,
    59  			Line:     line,
    60  		}
    61  		frames = append(frames, frame)
    62  	}
    63  	return frames
    64  }