diff --git a/examples/simple_plugin/go.mod b/examples/simple_plugin/go.mod index f0c88aa59f..20fc7dd664 100644 --- a/examples/simple_plugin/go.mod +++ b/examples/simple_plugin/go.mod @@ -37,6 +37,7 @@ require ( github.com/cloudquery/plugin-pb-go v1.27.5 // indirect github.com/cloudquery/plugin-sdk/v2 v2.7.0 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/getsentry/sentry-go v0.40.0 // indirect github.com/ghodss/yaml v1.0.0 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect diff --git a/examples/simple_plugin/go.sum b/examples/simple_plugin/go.sum index d224627187..213e01443c 100644 --- a/examples/simple_plugin/go.sum +++ b/examples/simple_plugin/go.sum @@ -71,8 +71,12 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= +github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -135,6 +139,9 @@ github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQ github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/go.mod b/go.mod index 63e48d11ac..99fa718def 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/cloudquery/codegen v0.3.35 github.com/cloudquery/plugin-pb-go v1.27.5 github.com/cloudquery/plugin-sdk/v2 v2.7.0 + github.com/getsentry/sentry-go v0.40.0 github.com/goccy/go-json v0.10.5 github.com/golang/mock v1.6.0 github.com/google/go-cmp v0.7.0 diff --git a/go.sum b/go.sum index 767d8a3afd..49a9c91bff 100644 --- a/go.sum +++ b/go.sum @@ -74,8 +74,12 @@ github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxK github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= +github.com/getsentry/sentry-go v0.40.0 h1:VTJMN9zbTvqDqPwheRVLcp0qcUcM+8eFivvGocAaSbo= +github.com/getsentry/sentry-go v0.40.0/go.mod h1:eRXCoh3uvmjQLY6qu63BjUZnaBu5L5WhMV1RwYO8W5s= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= +github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= +github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= @@ -138,6 +142,9 @@ github.com/oapi-codegen/runtime v1.1.2 h1:P2+CubHq8fO4Q6fV1tqDBZHCwpVpvPg7oKiYzQ github.com/oapi-codegen/runtime v1.1.2/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg= github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU= github.com/pierrec/lz4/v4 v4.1.22/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4= +github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4= +github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= diff --git a/scheduler/queue/worker.go b/scheduler/queue/worker.go index be4864d628..451421c443 100644 --- a/scheduler/queue/worker.go +++ b/scheduler/queue/worker.go @@ -13,6 +13,7 @@ import ( "github.com/cloudquery/plugin-sdk/v4/scheduler/metrics" "github.com/cloudquery/plugin-sdk/v4/scheduler/resolvers" "github.com/cloudquery/plugin-sdk/v4/schema" + "github.com/getsentry/sentry-go" "github.com/rs/zerolog" "github.com/samber/lo" "go.opentelemetry.io/otel" @@ -103,6 +104,10 @@ func (w *worker) resolveTable(ctx context.Context, table *schema.Table, client s stack := fmt.Sprintf("%s\n%s", err, string(debug.Stack())) logger.Error().Interface("error", err).Str("stack", stack).Msg("table resolver finished with panic") w.metrics.AddPanics(ctx, 1, selector) + sentry.WithScope(func(scope *sentry.Scope) { + scope.SetTag("table", table.Name) + sentry.CurrentHub().CaptureMessage(stack) + }) } close(res) }() diff --git a/scheduler/resolvers/resolvers.go b/scheduler/resolvers/resolvers.go index 2d20aee9eb..365469c8a9 100644 --- a/scheduler/resolvers/resolvers.go +++ b/scheduler/resolvers/resolvers.go @@ -9,6 +9,7 @@ import ( "github.com/cloudquery/plugin-sdk/v4/caser" "github.com/cloudquery/plugin-sdk/v4/scheduler/metrics" "github.com/cloudquery/plugin-sdk/v4/schema" + "github.com/getsentry/sentry-go" "github.com/rs/zerolog" "github.com/thoas/go-funk" ) @@ -20,6 +21,11 @@ func resolveColumn(ctx context.Context, logger zerolog.Logger, m *metrics.Metric stack := fmt.Sprintf("%s\n%s", err, string(debug.Stack())) logger.Error().Str("column", column.Name).Interface("error", err).TimeDiff("duration", time.Now(), columnStartTime).Str("stack", stack).Msg("column resolver finished with panic") m.AddPanics(ctx, 1, selector) + sentry.WithScope(func(scope *sentry.Scope) { + scope.SetTag("table", resource.Table.Name) + scope.SetTag("column", column.Name) + sentry.CurrentHub().CaptureMessage(stack) + }) } }() diff --git a/scheduler/scheduler_dfs.go b/scheduler/scheduler_dfs.go index 515cd9bc77..b90738ed69 100644 --- a/scheduler/scheduler_dfs.go +++ b/scheduler/scheduler_dfs.go @@ -13,6 +13,7 @@ import ( "github.com/cloudquery/plugin-sdk/v4/scheduler/metrics" "github.com/cloudquery/plugin-sdk/v4/scheduler/resolvers" "github.com/cloudquery/plugin-sdk/v4/schema" + "github.com/getsentry/sentry-go" "github.com/samber/lo" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -119,6 +120,10 @@ func (s *syncClient) resolveTableDfs(ctx context.Context, table *schema.Table, c stack := fmt.Sprintf("%s\n%s", err, string(debug.Stack())) logger.Error().Interface("error", err).Str("stack", stack).Msg("table resolver finished with panic") s.metrics.AddPanics(ctx, 1, selector) + sentry.WithScope(func(scope *sentry.Scope) { + scope.SetTag("table", table.Name) + sentry.CurrentHub().CaptureMessage(stack) + }) } close(res) }() diff --git a/serve/plugin.go b/serve/plugin.go index 3038e46b78..397431768a 100644 --- a/serve/plugin.go +++ b/serve/plugin.go @@ -2,10 +2,12 @@ package serve import ( "context" + "errors" "fmt" "net" "os" "os/signal" + "strconv" "strings" "syscall" @@ -13,6 +15,7 @@ import ( "github.com/cloudquery/plugin-sdk/v4/plugin" "github.com/cloudquery/plugin-sdk/v4/premium" "github.com/cloudquery/plugin-sdk/v4/types" + "github.com/getsentry/sentry-go" pbDestinationV0 "github.com/cloudquery/plugin-pb-go/pb/destination/v0" pbDestinationV1 "github.com/cloudquery/plugin-pb-go/pb/destination/v1" @@ -37,6 +40,7 @@ type PluginServe struct { plugin *plugin.Plugin args []string destinationV0V1Server bool + sentryDSN string testListener bool testListenerConn *bufconn.Listener versions []int @@ -44,6 +48,12 @@ type PluginServe struct { type PluginOption func(*PluginServe) +func WithPluginSentryDSN(dsn string) PluginOption { + return func(s *PluginServe) { + s.sentryDSN = dsn + } +} + // WithDestinationV0V1Server is used to include destination v0 and v1 server to work // with older sources func WithDestinationV0V1Server() PluginOption { @@ -123,6 +133,11 @@ func (s *PluginServe) newCmdPluginServe() *cobra.Command { Long: servePluginShort, Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { + doSentry, _ := strconv.ParseBool(os.Getenv("CQ_SENTRY_ENABLED")) + if doSentry && noSentry { + return errors.New("CQ_SENTRY_ENABLED and --no-sentry cannot be used together") + } + zerologLevel, err := zerolog.ParseLevel(logLevel.String()) if err != nil { return err @@ -204,6 +219,33 @@ func (s *PluginServe) newCmdPluginServe() *cobra.Command { Versions: []int32{0, 1, 2, 3}, }) + version := s.plugin.Version() + + if doSentry && len(s.sentryDSN) > 0 && !strings.EqualFold(version, "development") && !noSentry { + err = sentry.Init(sentry.ClientOptions{ + Dsn: s.sentryDSN, + Debug: false, + AttachStacktrace: false, + Release: version, + Transport: sentry.NewHTTPSyncTransport(), + ServerName: "oss", // set to "oss" on purpose to avoid sending any identifying information + // https://docs.sentry.io/platforms/go/configuration/options/#removing-default-integrations + Integrations: func(integrations []sentry.Integration) []sentry.Integration { + var filteredIntegrations []sentry.Integration + for _, integration := range integrations { + if integration.Name() == "Modules" { + continue + } + filteredIntegrations = append(filteredIntegrations, integration) + } + return filteredIntegrations + }, + }) + if err != nil { + log.Error().Err(err).Msg("Error initializing sentry") + } + } + ctx := cmd.Context() c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, syscall.SIGTERM)