-
Notifications
You must be signed in to change notification settings - Fork 0
feat(reporter/sentry): filtering funcs to set custom error level on sentry #18
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
01fd3c0
4a03d7a
a2fea3d
cdd19d5
3e33ddb
c51e6c2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,37 +1,55 @@ | ||
| package sentry | ||
|
|
||
| import ( | ||
| "context" | ||
| "io" | ||
| "os" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/getsentry/sentry-go" | ||
| uerrors "github.com/upfluence/errors" | ||
| "github.com/upfluence/errors/base" | ||
| "github.com/upfluence/errors/reporter" | ||
| ) | ||
|
|
||
| var defaultOptions = Options{ | ||
| Tags: make(map[string]string), | ||
| SentryOptions: sentry.ClientOptions{ | ||
| Dsn: os.Getenv("SENTRY_DSN"), | ||
| Environment: os.Getenv("ENV"), | ||
| SendDefaultPII: true, | ||
| }, | ||
| TagWhitelist: toStringMap( | ||
| []string{reporter.RemoteIP, reporter.RemotePort, reporter.DomainKey}, | ||
| ), | ||
| Timeout: time.Minute, | ||
| TagBlacklist: []func(string) bool{ | ||
| stringEqual(reporter.TransactionKey), | ||
| stringEqual(reporter.UserEmailKey), | ||
| stringEqual(reporter.UserIDKey), | ||
| stringEqual(reporter.HTTPRequestProtoKey), | ||
| stringEqual(reporter.HTTPRequestPathKey), | ||
| stringEqual(reporter.HTTPRequestHostKey), | ||
| stringEqual(reporter.HTTPRequestMethodKey), | ||
| stringEqual(reporter.HTTPRequestBodyKey), | ||
| stringPrefix(reporter.HTTPRequestHeaderKeyPrefix), | ||
| stringPrefix(reporter.HTTPRequestQueryValuesKeyPrefix), | ||
| }, | ||
| type ErrorLevelMapper func(error) sentry.Level | ||
|
|
||
| var defaultErrorLevelMappers = []ErrorLevelMapper{ | ||
| ErrorIsLevel(context.DeadlineExceeded, sentry.LevelWarning), | ||
| ErrorIsLevel(context.Canceled, sentry.LevelWarning), | ||
| ErrorIsLevel(io.EOF, sentry.LevelWarning), | ||
| ErrorCauseTextContainsLevel("net/http: TLS handshake timeout", sentry.LevelWarning), | ||
| ErrorCauseTextContainsLevel("operation was canceled", sentry.LevelWarning), | ||
| ErrorCauseTextContainsLevel("EOF", sentry.LevelWarning), | ||
| } | ||
|
|
||
| func defaultOptions() Options { | ||
| return Options{ | ||
| Tags: make(map[string]string), | ||
| SentryOptions: sentry.ClientOptions{ | ||
| Dsn: os.Getenv("SENTRY_DSN"), | ||
| Environment: os.Getenv("ENV"), | ||
| SendDefaultPII: true, | ||
| }, | ||
| TagWhitelist: toStringMap( | ||
| []string{reporter.RemoteIP, reporter.RemotePort, reporter.DomainKey}, | ||
| ), | ||
| Timeout: time.Minute, | ||
| TagBlacklist: []func(string) bool{ | ||
| stringEqual(reporter.TransactionKey), | ||
| stringEqual(reporter.UserEmailKey), | ||
| stringEqual(reporter.UserIDKey), | ||
| stringEqual(reporter.HTTPRequestProtoKey), | ||
| stringEqual(reporter.HTTPRequestPathKey), | ||
| stringEqual(reporter.HTTPRequestHostKey), | ||
| stringEqual(reporter.HTTPRequestMethodKey), | ||
| stringEqual(reporter.HTTPRequestBodyKey), | ||
| stringPrefix(reporter.HTTPRequestHeaderKeyPrefix), | ||
| stringPrefix(reporter.HTTPRequestQueryValuesKeyPrefix), | ||
| }, | ||
| ErrorLevelMappers: defaultErrorLevelMappers, | ||
| } | ||
| } | ||
|
|
||
| func stringEqual(x string) func(string) bool { | ||
|
|
@@ -52,6 +70,44 @@ func toStringMap(vs []string) map[string]struct{} { | |
| return res | ||
| } | ||
|
|
||
| // ErrorIsLevel creates an ErrorLevelMapper of the passed level that checks if | ||
| // reported errors are the same as the given sentinel error | ||
| func ErrorIsLevel(sentinel error, level sentry.Level) ErrorLevelMapper { | ||
| return func(err error) sentry.Level { | ||
| if uerrors.Is(err, sentinel) { | ||
| return level | ||
| } | ||
|
|
||
| return "" | ||
| } | ||
| } | ||
|
|
||
| // ErrorIsOfTypeLevel creates an ErrorLevelMapper of the passed level that checks | ||
| // if reported errors are of the passed generic type | ||
| func ErrorIsOfTypeLevel[T error](level sentry.Level) ErrorLevelMapper { | ||
| return func(err error) sentry.Level { | ||
| if uerrors.IsOfType[T](err) { | ||
| return level | ||
| } | ||
|
|
||
| return "" | ||
| } | ||
| } | ||
|
|
||
| // ErrorCauseTextContainsLevel creates an ErrorLevelMapper of the passed level that checks | ||
| // if reported errors' cause's Error() text contains the passed string | ||
| func ErrorCauseTextContainsLevel(errorText string, level sentry.Level) ErrorLevelMapper { | ||
| return func(err error) sentry.Level { | ||
| rootCause := base.UnwrapAll(err).Error() | ||
|
|
||
| if strings.Contains(rootCause, errorText) { | ||
| return level | ||
| } | ||
|
|
||
| return "" | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nil error causes panic in ErrorCauseTextContainsLevel mapperThe |
||
| } | ||
|
|
||
| type Options struct { | ||
| Tags map[string]string | ||
|
|
||
|
|
@@ -60,6 +116,8 @@ type Options struct { | |
|
|
||
| TagWhitelist map[string]struct{} | ||
| TagBlacklist []func(string) bool | ||
|
|
||
| ErrorLevelMappers []ErrorLevelMapper | ||
| } | ||
|
|
||
| func (o Options) client() (*sentry.Client, error) { | ||
|
|
@@ -74,10 +132,25 @@ func (o Options) client() (*sentry.Client, error) { | |
|
|
||
| type Option func(*Options) | ||
|
|
||
| // WithTags allows for custom tags to be given to the Reporter | ||
cursor[bot] marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| func WithTags(tags map[string]string) Option { | ||
| return func(opts *Options) { | ||
| for k, v := range tags { | ||
| opts.Tags[k] = v | ||
| } | ||
| } | ||
| } | ||
|
|
||
| // AppendErrorLevelMappers adds the passed funcs to the ErrorLevelMappers of the Reporter | ||
| func AppendErrorLevelMappers(funcs ...ErrorLevelMapper) Option { | ||
| return func(opts *Options) { | ||
| opts.ErrorLevelMappers = append(opts.ErrorLevelMappers, funcs...) | ||
| } | ||
| } | ||
|
|
||
| // ReplaceErrorLevelMappers replaces the ErrorLevelMappers of the Reporter with the passed ones | ||
| func ReplaceErrorLevelMappers(funcs []ErrorLevelMapper) Option { | ||
| return func(opts *Options) { | ||
| opts.ErrorLevelMappers = funcs | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -30,13 +30,14 @@ type Reporter struct { | |
|
|
||
| tagWhitelist []func(string) bool | ||
| tagBlacklist []func(string) bool | ||
| levelMappers []ErrorLevelMapper | ||
|
|
||
| timeout time.Duration | ||
| } | ||
|
|
||
| // NewReporter creates a new Sentry reporter with the given options. | ||
| func NewReporter(os ...Option) (*Reporter, error) { | ||
| var opts = defaultOptions | ||
| var opts = defaultOptions() | ||
|
|
||
| for _, o := range os { | ||
| o(&opts) | ||
|
|
@@ -58,6 +59,7 @@ func NewReporter(os ...Option) (*Reporter, error) { | |
| }, | ||
| tagBlacklist: opts.TagBlacklist, | ||
| timeout: opts.Timeout, | ||
| levelMappers: opts.ErrorLevelMappers, | ||
| }, nil | ||
| } | ||
|
|
||
|
|
@@ -121,26 +123,26 @@ func (r *Reporter) buildEvent(err error, opts reporter.ReportOptions) *sentry.Ev | |
| return nil | ||
| } | ||
|
|
||
| ts := tags.GetTags(err) | ||
| errorTags := tags.GetTags(err) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nitpick: the repository is already named Same feedback for:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The problem here is that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that makes sends for
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah, can do when I next get to work on this one 👍 |
||
|
|
||
| if ts == nil && len(opts.Tags) > 0 { | ||
| ts = make(map[string]interface{}, len(opts.Tags)) | ||
| if errorTags == nil && len(opts.Tags) > 0 { | ||
| errorTags = make(map[string]interface{}, len(opts.Tags)) | ||
| } | ||
|
|
||
| for k, v := range opts.Tags { | ||
| if _, ok := ts[k]; !ok { | ||
| ts[k] = v | ||
| if _, ok := errorTags[k]; !ok { | ||
| errorTags[k] = v | ||
| } | ||
| } | ||
|
|
||
| evt := sentry.NewEvent() | ||
|
|
||
| evt.Level = sentry.LevelError | ||
| evt.Level = r.computeLevel(err) | ||
| evt.Timestamp = time.Now() | ||
| evt.Message = err.Error() | ||
| evt.Transaction = transactionName(ts) | ||
| evt.User = buildUser(ts) | ||
| evt.Request = buildRequest(ts) | ||
| evt.Transaction = transactionName(errorTags) | ||
| evt.User = buildUser(errorTags) | ||
| evt.Request = buildRequest(errorTags) | ||
|
|
||
| cause := base.UnwrapAll(err) | ||
|
|
||
|
|
@@ -153,7 +155,7 @@ func (r *Reporter) buildEvent(err error, opts reporter.ReportOptions) *sentry.Ev | |
| }, | ||
| } | ||
|
|
||
| for k, v := range ts { | ||
| for k, v := range errorTags { | ||
| r.appendTag(k, v, evt) | ||
| } | ||
|
|
||
|
|
@@ -164,6 +166,16 @@ func (r *Reporter) buildEvent(err error, opts reporter.ReportOptions) *sentry.Ev | |
| return evt | ||
| } | ||
|
|
||
| func (r *Reporter) computeLevel(err error) sentry.Level { | ||
| for _, errFunc := range r.levelMappers { | ||
| if level := errFunc(err); level != "" { | ||
| return level | ||
| } | ||
| } | ||
|
|
||
| return sentry.LevelError | ||
| } | ||
|
|
||
| func extractStacktrace(err error, n int) *sentry.Stacktrace { | ||
| var s sentry.Stacktrace | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I saw that you applied the comment https://github.com/upfluence/errors/pull/18/changes#r2578258351 in the
reporter.gofile can you apply the comment in this file as wellThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, for exported names, we had that conversation previously with @Sypheos and @karitham : #18 (comment), not sure it's a very good idea for clarity's sake to just call them
LevelFuncs, for instance, unless you have a better idea?For private constructions I don't mind