From ac1c568777eecd684e2030fd42b4f46ff31e76f9 Mon Sep 17 00:00:00 2001 From: Volodymyr Stoiko <me@volodymyrstoiko.com> Date: Tue, 10 Sep 2024 03:34:46 +0300 Subject: [PATCH] Get Sentry DSN from API (#92) * Read sentry DSN from API * naming * fix * fix * Add option to enabled/disable sentry via env var (#93) --- main.go | 40 ++++++++++++-------- pkg/sentry/sentry.go | 88 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 pkg/sentry/sentry.go diff --git a/main.go b/main.go index cb4ebc6..fa2919f 100644 --- a/main.go +++ b/main.go @@ -23,6 +23,8 @@ import ( "k8s.io/client-go/rest" "github.com/kubeshark/tracer/pkg/health" + + sentrypkg "github.com/kubeshark/tracer/pkg/sentry" ) const ( @@ -41,8 +43,6 @@ var globCbuf = flag.Int("cbuf", 0, fmt.Sprintf("Keep last N packets in circular var disableEbpfCapture = flag.Bool("disable-ebpf", false, "Disable capture packet via eBPF") var disableTlsLog = flag.Bool("disable-tls-log", false, "Disable tls logging") -const sentryDsn = "https://c0b7399e76173c4601a82aab28eb4be8@o4507855877505024.ingest.us.sentry.io/4507886789263360" - type sslListArray []string func (i *sslListArray) String() string { @@ -58,25 +58,33 @@ var sslLibsGlobal sslListArray var tracer *Tracer func main() { - // To initialize Sentry's handler, you need to initialize Sentry itself beforehand - if err := sentry.Init(sentry.ClientOptions{ - Dsn: sentryDsn, - EnableTracing: true, - // Set TracesSampleRate to 1.0 to capture 100% - // of transactions for tracing. - // We recommend adjusting this value in production, - TracesSampleRate: 1.0, - Release: version.Ver, - }); err != nil { - log.Error().Err(err).Msg("Sentry initialization failed:") - } else { - defer sentry.Flush(2 * time.Second) + var sentryDSN string + if sentrypkg.IsSentryEnabled() { + sentryDSN, error := sentrypkg.GetDSN(context.Background()) + if error != nil { + log.Error().Err(error).Msg("Failed to get Sentry DSN") + } + + // To initialize Sentry's handler, you need to initialize Sentry itself beforehand + if err := sentry.Init(sentry.ClientOptions{ + Dsn: sentryDSN, + EnableTracing: true, + // Set TracesSampleRate to 1.0 to capture 100% + // of transactions for tracing. + // We recommend adjusting this value in production, + TracesSampleRate: 1.0, + Release: version.Ver, + }); err != nil { + log.Error().Err(err).Msg("Sentry initialization failed:") + } else { + defer sentry.Flush(2 * time.Second) + } } zerolog.SetGlobalLevel(zerolog.InfoLevel) w, err := zlogsentry.New( - sentryDsn, + sentryDSN, ) if err != nil { stdlog.Fatal(err) diff --git a/pkg/sentry/sentry.go b/pkg/sentry/sentry.go new file mode 100644 index 0000000..9c26f8f --- /dev/null +++ b/pkg/sentry/sentry.go @@ -0,0 +1,88 @@ +package sentry + +import ( + "bytes" + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "os" + + "github.com/hashicorp/go-retryablehttp" + "github.com/kubeshark/tracer/pkg/version" + "github.com/rs/zerolog/log" +) + +type Request struct { + Service string `json:"service"` + Version string `json:"version"` +} + +type DSNResponse struct { + DSN string `json:"dsn"` +} + +func IsSentryEnabled() bool { + return os.Getenv("SENTRY_ENABLED") == "true" +} + +func GetDSN(ctx context.Context) (string, error) { + + retryClient := retryablehttp.NewClient() + retryClient.RetryMax = 3 // Max retry attempts + + client := retryClient.StandardClient() + + endpoint := getDSNEndpoint() + + reqBody := Request{ + Service: "tracer", + Version: version.Ver, + } + + jsonData, err := json.Marshal(reqBody) + if err != nil { + return "", fmt.Errorf("error marshalling request body: %v", err) + } + + req, err := http.NewRequestWithContext(ctx, "POST", endpoint, bytes.NewBuffer(jsonData)) + if err != nil { + return "", fmt.Errorf("error creating POST request: %v", err) + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := client.Do(req) + if err != nil { + return "", fmt.Errorf("error making POST request: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + return "", nil // Return empty string if not 200 + } + + body, err := io.ReadAll(resp.Body) + if err != nil { + return "", fmt.Errorf("error reading response body: %v", err) + } + + var dsnResp DSNResponse + err = json.Unmarshal(body, &dsnResp) + if err != nil { + return "", fmt.Errorf("error unmarshalling response body: %v", err) + } + + return dsnResp.DSN, nil +} + +func getDSNEndpoint() string { + apiUrl, ok := os.LookupEnv("KUBESHARK_CLOUD_API_URL") + if !ok { + log.Info().Msg("KUBESHARK_CLOUD_API_URL wasn't found. Defaulting to https://api.kubeshark.co") + apiUrl = "https://api.kubeshark.co" + } + + return fmt.Sprintf("%s/sentry", apiUrl) +}