Add support for error (panic) reporting through Sentry

This commit is contained in:
Denis Arh
2019-07-03 16:35:06 +02:00
parent 4973638e2a
commit 60ad32e440
40 changed files with 3465 additions and 17 deletions
+24
View File
@@ -5,6 +5,7 @@ import (
"os"
"time"
"github.com/getsentry/sentry-go"
"go.uber.org/zap"
"github.com/cortezaproject/corteza-server/internal/auth"
@@ -28,6 +29,29 @@ func InitGeneralServices(logOpt *options.LogOpt, smtpOpt *options.SMTPOpt, jwtOp
)
}
func InitSentry(sentryOpt *options.SentryOpt) error {
if sentryOpt.DSN == "" {
return nil
}
return sentry.Init(sentry.ClientOptions{
Dsn: sentryOpt.DSN,
Debug: sentryOpt.Debug,
AttachStacktrace: sentryOpt.AttachStacktrace,
SampleRate: sentryOpt.SampleRate,
MaxBreadcrumbs: sentryOpt.MaxBreadcrumbs,
IgnoreErrors: nil,
BeforeSend: nil,
BeforeBreadcrumb: nil,
Integrations: nil,
Transport: nil,
ServerName: sentryOpt.ServerName,
Release: sentryOpt.Release,
Dist: sentryOpt.Dist,
Environment: sentryOpt.Environment,
})
}
func HandleError(err error) {
if err == nil {
return
+16
View File
@@ -50,6 +50,11 @@ func fill(opt interface{}, pfix string) {
continue
}
if f.Kind() == reflect.Float32 {
v.FieldByName(t.Name).SetFloat(float64(EnvFloat32(pfix, tag, float32(f.Float()))))
continue
}
panic("unsupported type/kind for field " + t.Name)
}
@@ -94,6 +99,17 @@ func EnvInt(pfix, key string, def int) int {
return def
}
func EnvFloat32(pfix, key string, def float32) float32 {
for _, key = range makeEnvKeys(pfix, key) {
if val, has := os.LookupEnv(key); has {
if i, err := cast.ToFloat32E(val); err == nil {
return i
}
}
}
return def
}
func EnvDuration(pfix, key string, def time.Duration) time.Duration {
for _, key = range makeEnvKeys(pfix, key) {
if val, has := os.LookupEnv(key); has {
+11 -4
View File
@@ -6,9 +6,10 @@ import (
type (
HTTPOpt struct {
Addr string `env:"HTTP_ADDR"`
Logging bool `env:"HTTP_LOG_REQUESTS"`
Tracing bool `env:"HTTP_ERROR_TRACING"`
Addr string `env:"HTTP_ADDR"`
LogRequest bool `env:"HTTP_LOG_REQUEST"`
LogResponse bool `env:"HTTP_LOG_RESPONSE"`
Tracing bool `env:"HTTP_ERROR_TRACING"`
EnableVersionRoute bool `env:"HTTP_ENABLE_VERSION_ROUTE"`
EnableDebugRoute bool `env:"HTTP_ENABLE_DEBUG_ROUTE"`
@@ -17,13 +18,16 @@ type (
MetricsServiceLabel string `env:"HTTP_METRICS_NAME"`
MetricsUsername string `env:"HTTP_METRICS_USERNAME"`
MetricsPassword string `env:"HTTP_METRICS_PASSWORD"`
EnablePanicReporting bool `env:"HTTP_REPORT_PANIC"`
}
)
func HTTP(pfix string) (o *HTTPOpt) {
o = &HTTPOpt{
Addr: ":80",
Logging: true,
LogRequest: false,
LogResponse: false,
Tracing: false,
EnableVersionRoute: true,
EnableDebugRoute: false,
@@ -31,6 +35,9 @@ func HTTP(pfix string) (o *HTTPOpt) {
MetricsServiceLabel: "corteza",
MetricsUsername: "metrics",
// Reports panics to Sentry throught HTTP middleware
EnablePanicReporting: true,
// Setting metrics password to random string to prevent security accidents...
MetricsPassword: string(rand.Bytes(5)),
}
+34
View File
@@ -0,0 +1,34 @@
package options
import (
"github.com/cortezaproject/corteza-server/internal/version"
)
type (
SentryOpt struct {
DSN string `env:"SENTRY_DSN"`
Debug bool `env:"SENTRY_DEBUG"`
AttachStacktrace bool `env:"SENTRY_ATTACH_STACKTRACE"`
SampleRate float32 `env:"SENTRY_SAMPLE_RATE"`
MaxBreadcrumbs int `env:"SENTRY_MAX_BREADCRUMBS"`
ServerName string `env:"SENTRY_SERVERNAME"`
Release string `env:"SENTRY_RELEASE"`
Dist string `env:"SENTRY_DIST"`
Environment string `env:"SENTRY_ENVIRONMENT"`
}
)
func Sentry(pfix string) (o *SentryOpt) {
o = &SentryOpt{
AttachStacktrace: true,
MaxBreadcrumbs: 0,
Release: version.Version,
}
fill(o, pfix)
return
}
+9
View File
@@ -3,6 +3,7 @@ package cli
import (
"context"
"github.com/getsentry/sentry-go"
"github.com/go-chi/chi"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@@ -48,6 +49,7 @@ type (
HttpClientOpt *options.HttpClientOpt
DbOpt *options.DBOpt
ProvisionOpt *options.ProvisionOpt
SentryOpt *options.SentryOpt
// DB Connection name, defaults to ServiceName
DatabaseName string
@@ -179,6 +181,7 @@ func (c *Config) Init() {
c.HttpClientOpt = options.HttpClient(c.EnvPrefix)
c.DbOpt = options.DB(c.ServiceName)
c.ProvisionOpt = options.Provision(c.ServiceName)
c.SentryOpt = options.Sentry(c.EnvPrefix)
if c.RootCommandDBSetup == nil {
c.RootCommandDBSetup = Runners{func(ctx context.Context, cmd *cobra.Command, c *Config) (err error) {
@@ -213,6 +216,11 @@ func (c *Config) MakeCLI(ctx context.Context) (cmd *cobra.Command) {
Use: c.RootCommandName,
TraverseChildren: true,
PersistentPreRunE: func(cmd *cobra.Command, args []string) (err error) {
if err = InitSentry(c.SentryOpt); err != nil {
c.Log.Error("could not initialize Sentry", zap.Error(err))
}
defer sentry.Recover()
InitGeneralServices(c.LogOpt, c.SmtpOpt, c.JwtOpt, c.HttpClientOpt)
err = c.RootCommandDBSetup.Run(ctx, cmd, c)
@@ -232,6 +240,7 @@ func (c *Config) MakeCLI(ctx context.Context) (cmd *cobra.Command) {
}
serveApiCmd := c.ApiServer.Command(ctx, c.ApiServerCommandName, c.EnvPrefix, func(ctx context.Context) (err error) {
defer sentry.Recover()
return c.ApiServerPreRun.Run(ctx, cmd, c)
})