From ca03ff9fbc278ae2dfc375359f960d2ca7cf3afc Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Fri, 13 Sep 2024 15:02:11 +0200 Subject: [PATCH] feat: report bug to sentry (#4328) (cherry picked from commit 0adabfdc1c8f31685276fe5fb23a71f142284ef2) # Conflicts: # go.mod # ignite/internal/analytics/analytics.go --- changelog.md | 25 ++++++++++++++ go.mod | 7 ++++ ignite/cmd/ignite/main.go | 7 ++-- ignite/internal/analytics/analytics.go | 26 ++++++++++++++ ignite/pkg/errors/xerrors.go | 33 ++++++++++++++---- ignite/pkg/sentry/sentry.go | 48 ++++++++++++++++++++++++++ 6 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 ignite/pkg/sentry/sentry.go diff --git a/changelog.md b/changelog.md index a5c6975228..6cc689ce09 100644 --- a/changelog.md +++ b/changelog.md @@ -5,6 +5,31 @@ ### Changes - [#4357](https://github.com/ignite/cli/pull/4357) Bump chain dependencies (store, ics, log, etc) +- [#4094](https://github.com/ignite/cli/pull/4094) Scaffolding a multi-index map using `ignite s map foo bar baz --index foobar,foobaz` is no longer supported. Use one index instead of use `collections.IndexedMap`. +- [#4058](https://github.com/ignite/cli/pull/4058) Simplify scaffolded modules by including `ValidateBasic()` logic in message handler. +- [#4058](https://github.com/ignite/cli/pull/4058) Use `address.Codec` instead of `AccAddressFromBech32`. +- [#3993](https://github.com/ignite/cli/pull/3993) Oracle scaffolding was deprecated and has been removed +- [#3962](https://github.com/ignite/cli/pull/3962) Rename all RPC endpoints and autocli commands generated for `map`/`list`/`single` types +- [#3976](https://github.com/ignite/cli/pull/3976) Remove error checks for Cobra command value get calls +- [#4002](https://github.com/ignite/cli/pull/4002) Bump buf build +- [#4008](https://github.com/ignite/cli/pull/4008) Rename `pkg/yaml` to `pkg/xyaml` +- [#4075](https://github.com/ignite/cli/pull/4075) Use `gopkg.in/yaml.v3` instead `gopkg.in/yaml.v2` +- [#4118](https://github.com/ignite/cli/pull/4118) Version scaffolded protos as `v1` to follow SDK structure. +- [#4167](https://github.com/ignite/cli/pull/4167) Scaffold `int64` instead of `int32` when a field type is `int` +- [#4159](https://github.com/ignite/cli/pull/4159) Enable gci linter +- [#4160](https://github.com/ignite/cli/pull/4160) Enable copyloopvar linter +- [#4162](https://github.com/ignite/cli/pull/4162) Enable errcheck linter +- [#4189](https://github.com/ignite/cli/pull/4189) Deprecate `ignite node` for `ignite connect` app +- [#4290](https://github.com/ignite/cli/pull/4290) Remove ignite ics logic from ignite cli (this functionality will be in the `consumer` app) +- [#4295](https://github.com/ignite/cli/pull/4295) Stop scaffolding `pulsar` files +- [#4317](https://github.com/ignite/cli/pull/4317) Remove xchisel dependency +- [#4328](https://github.com/ignite/cli/pull/4328) Send ignite bug report to sentry. Opt out the same way as for usage analytics + +### Fixes + +- [#4000](https://github.com/ignite/cli/pull/4000) Run all dry runners before the wet run in the `xgenny` pkg +- [#4091](https://github.com/ignite/cli/pull/4091) Fix race conditions in the plugin logic +- [#4128](https://github.com/ignite/cli/pull/4128) Check for duplicate proto fields in config ## [`v28.5.2`](https://github.com/ignite/cli/releases/tag/v28.5.2) diff --git a/go.mod b/go.mod index 8af22cdea6..91c42a38cb 100644 --- a/go.mod +++ b/go.mod @@ -35,6 +35,7 @@ require ( github.com/cosmos/gogoproto v1.7.0 github.com/emicklei/proto v1.12.2 github.com/emicklei/proto-contrib v0.15.0 + github.com/getsentry/sentry-go v0.27.0 github.com/go-delve/delve v1.21.0 github.com/go-git/go-git/v5 v5.12.0 github.com/go-openapi/analysis v0.23.0 @@ -222,10 +223,16 @@ require ( github.com/firefart/nonamedreturns v1.0.4 // indirect github.com/fsnotify/fsnotify v1.7.0 // indirect github.com/fzipp/gocyclo v0.6.0 // indirect +<<<<<<< HEAD github.com/getsentry/sentry-go v0.27.0 // indirect github.com/ghostiam/protogetter v0.3.5 // indirect github.com/go-chi/chi/v5 v5.0.13 // indirect github.com/go-critic/go-critic v0.11.2 // indirect +======= + github.com/ghostiam/protogetter v0.3.6 // indirect + github.com/go-chi/chi/v5 v5.0.12 // indirect + github.com/go-critic/go-critic v0.11.4 // indirect +>>>>>>> 0adabfdc (feat: report bug to sentry (#4328)) github.com/go-delve/liner v1.2.3-0.20231231155935-4726ab1d7f62 // indirect github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect github.com/go-git/go-billy/v5 v5.5.0 // indirect diff --git a/ignite/cmd/ignite/main.go b/ignite/cmd/ignite/main.go index 9a6acd8a1f..df414111f5 100644 --- a/ignite/cmd/ignite/main.go +++ b/ignite/cmd/ignite/main.go @@ -19,12 +19,13 @@ import ( "github.com/ignite/cli/v28/ignite/pkg/xstrings" ) +const exitCodeOK, exitCodeError = 0, 1 + func main() { os.Exit(run()) } func run() int { - const exitCodeOK, exitCodeError = 0, 1 ctx := clictx.From(context.Background()) cmd, cleanUp, err := ignitecmd.New(ctx) if err != nil { @@ -41,6 +42,7 @@ func run() int { } var wg sync.WaitGroup analytics.SendMetric(&wg, subCmd) + analytics.EnableSentry(&wg, ctx) err = cmd.ExecuteContext(ctx) if err != nil { @@ -77,7 +79,8 @@ func run() int { return exitCodeError } - wg.Wait() // waits for all metrics to be sent + // waits for analytics to finish + wg.Wait() return exitCodeOK } diff --git a/ignite/internal/analytics/analytics.go b/ignite/internal/analytics/analytics.go index 4b5936e26d..0fa77d0169 100644 --- a/ignite/internal/analytics/analytics.go +++ b/ignite/internal/analytics/analytics.go @@ -12,11 +12,20 @@ import ( "github.com/manifoldco/promptui" "github.com/spf13/cobra" +<<<<<<< HEAD "github.com/ignite/cli/v28/ignite/config" "github.com/ignite/cli/v28/ignite/pkg/gitpod" "github.com/ignite/cli/v28/ignite/pkg/matomo" "github.com/ignite/cli/v28/ignite/pkg/randstr" "github.com/ignite/cli/v28/ignite/version" +======= + "github.com/ignite/cli/v29/ignite/config" + "github.com/ignite/cli/v29/ignite/pkg/gitpod" + "github.com/ignite/cli/v29/ignite/pkg/matomo" + "github.com/ignite/cli/v29/ignite/pkg/randstr" + "github.com/ignite/cli/v29/ignite/pkg/sentry" + "github.com/ignite/cli/v29/ignite/version" +>>>>>>> 0adabfdc (feat: report bug to sentry (#4328)) ) const ( @@ -99,6 +108,23 @@ func SendMetric(wg *sync.WaitGroup, cmd *cobra.Command) { }() } +// EnableSentry enable errors reporting to Sentry. +func EnableSentry(wg *sync.WaitGroup, ctx context.Context) { + dntInfo, err := checkDNT() + if err != nil || dntInfo.DoNotTrack { + return + } + + closeSentry, err := sentry.InitSentry(ctx) + wg.Add(1) + go func() { + defer wg.Done() + if err == nil { + defer closeSentry() + } + }() +} + // checkDNT check if the user allow to track data or if the DO_NOT_TRACK // env var is set https://consoledonottrack.com/ func checkDNT() (anonIdentity, error) { diff --git a/ignite/pkg/errors/xerrors.go b/ignite/pkg/errors/xerrors.go index a09391020a..bf7815d6af 100644 --- a/ignite/pkg/errors/xerrors.go +++ b/ignite/pkg/errors/xerrors.go @@ -14,23 +14,45 @@ package errors import ( "github.com/cockroachdb/errors" + "github.com/getsentry/sentry-go" ) // New creates an error with a simple error message. // A stack trace is retained. -func New(msg string) error { return errors.New(msg) } +func New(msg string) error { + err := errors.New(msg) + sentry.CaptureException(err) + return err +} // Errorf aliases Newf(). -func Errorf(format string, args ...interface{}) error { return errors.Errorf(format, args...) } +func Errorf(format string, args ...interface{}) error { + err := errors.Errorf(format, args...) + sentry.CaptureException(err) + return err +} + +// WithStack annotates err with a stack trace at the point WithStack was called. +func WithStack(err error) error { + errWithStack := errors.WithStack(err) + sentry.CaptureException(errWithStack) + return errWithStack +} // Wrap wraps an error with a message prefix. A stack trace is retained. -func Wrap(err error, msg string) error { return errors.Wrap(err, msg) } +func Wrap(err error, msg string) error { + errWrap := errors.Wrap(err, msg) + sentry.CaptureException(errWrap) + return errWrap +} // Wrapf wraps an error with a formatted message prefix. A stack // trace is also retained. If the format is empty, no prefix is added, // but the extra arguments are still processed for reportable strings. func Wrapf(err error, format string, args ...interface{}) error { - return errors.Wrapf(err, format, args...) + errWrap := errors.Wrapf(err, format, args...) + sentry.CaptureException(errWrap) + return errWrap } // Unwrap accesses the direct cause of the error if any, otherwise @@ -52,6 +74,3 @@ func Is(err, reference error) bool { return errors.Is(err, reference) } // As(interface{}) bool such that As(target) returns true. As will panic if target // is not a non-nil pointer to a type which implements error or is of interface type. func As(err error, target interface{}) bool { return errors.As(err, target) } - -// WithStack annotates err with a stack trace at the point WithStack was called. -func WithStack(err error) error { return errors.WithStack(err) } diff --git a/ignite/pkg/sentry/sentry.go b/ignite/pkg/sentry/sentry.go new file mode 100644 index 0000000000..3189324291 --- /dev/null +++ b/ignite/pkg/sentry/sentry.go @@ -0,0 +1,48 @@ +package sentry + +import ( + "context" + "fmt" + "strings" + "time" + + "github.com/getsentry/sentry-go" + + "github.com/ignite/cli/v29/ignite/pkg/errors" + "github.com/ignite/cli/v29/ignite/version" +) + +const IgniteDNS = "https://bugs.ignite.com" + +func InitSentry(ctx context.Context) (deferMe func(), err error) { + sentrySyncTransport := sentry.NewHTTPSyncTransport() + sentrySyncTransport.Timeout = time.Second * 3 + + igniteInfo, err := version.GetInfo(ctx) + if err != nil { + return nil, errors.Errorf("failed to init sentry: %w", err) + } + + if err := sentry.Init(sentry.ClientOptions{ + Dsn: IgniteDNS, + Transport: sentrySyncTransport, + Environment: getEnvironment(igniteInfo.CLIVersion), + Release: fmt.Sprintf("ignite@%s", igniteInfo.CLIVersion), + SampleRate: 1.0, // get all events + }); err != nil { + return nil, errors.Errorf("failed to init sentry: %w", err) + } + + return func() { + sentry.Recover() + sentry.Flush(time.Second * 2) + }, nil +} + +func getEnvironment(igniteVersion string) string { + if strings.Contains(igniteVersion, "dev") { + return "development" + } + + return "production" +}