diff --git a/docs/platforms/go/common/enriching-events/scopes/index.mdx b/docs/platforms/go/common/enriching-events/scopes/index.mdx index a307f4d3df0f11..8177327079e5f3 100644 --- a/docs/platforms/go/common/enriching-events/scopes/index.mdx +++ b/docs/platforms/go/common/enriching-events/scopes/index.mdx @@ -72,6 +72,22 @@ made will stay isolated within the call more easily isolate pieces of context information to specific locations in your code or even call to briefly remove all context information. +### Using + + and both modify the active scope, but they differ in how long the change lasts: + +- updates the current scope and keeps the change until you unset it or clear the scope. +- adds a child scope. Call to restore the previous scope, usually with `defer`. +- clones the current scope for a callback and restores it automatically when the callback returns. + +In Go, returns the new scope so you can configure it directly: + +```go +scope := sentry.PushScope() +defer sentry.PopScope() +scope.SetTag("request.type", "background") +``` + ## Setting Attributes You can set typed attributes on the scope using `SetAttributes`. These attributes are attached to logs and metrics emitted within the scope. Attributes use the `attribute` package for type safety. diff --git a/docs/platforms/go/common/logs/logrus.mdx b/docs/platforms/go/common/logs/logrus.mdx index 3c1cccc4789f7a..b9c59f5605160b 100644 --- a/docs/platforms/go/common/logs/logrus.mdx +++ b/docs/platforms/go/common/logs/logrus.mdx @@ -1,6 +1,6 @@ --- title: Logrus -description: "Integrate Logrus with Sentry to capture and send both logs and events." +description: "Integrate Logrus with Sentry to capture structured logs." sidebar_order: 10 --- @@ -28,12 +28,13 @@ go get github.com/getsentry/sentry-go/logrus ### Options `sentrylogrus` provides two types of hooks to configure the integration with Sentry. Both hooks accept these options: + - **Levels**: A slice of `logrus.Level` specifying which log levels to capture - **ClientOptions**: Standard `sentry.ClientOptions` for configuration ## Verify -To integrate Sentry with Logrus, you can set up both log hooks and event hooks to capture different types of data at various log levels. +To integrate Sentry with Logrus, configure the log hook with the levels you want to send as structured logs. ```go // Initialize Sentry SDK @@ -54,44 +55,29 @@ if client == nil { log.Fatalf("Sentry client is nil") } -// Create log hook to send logs on Info level +// Send selected log levels as structured logs. logHook := sentrylogrus.NewLogHookFromClient( - []logrus.Level{logrus.InfoLevel}, - client, -) - -// Create event hook to send events on Error, Fatal, Panic levels -eventHook := sentrylogrus.NewEventHookFromClient( - []logrus.Level{ - logrus.ErrorLevel, - logrus.FatalLevel, - logrus.PanicLevel, - }, + []logrus.Level{logrus.InfoLevel, logrus.WarnLevel, logrus.ErrorLevel}, client, ) -defer eventHook.Flush(5 * time.Second) defer logHook.Flush(5 * time.Second) -logger.AddHook(eventHook) logger.AddHook(logHook) -// Flushes before calling os.Exit(1) when using logger.Fatal -// (else all defers are not called, and Sentry does not have time to send the event) +// Flush before calling os.Exit(1) when using logger.Fatal. logrus.RegisterExitHandler(func() { - eventHook.Flush(5 * time.Second) logHook.Flush(5 * time.Second) }) -// Info level is sent as a log to Sentry +// Sending an info level log to Sentry. logger.Infof("Application has started") // Example of logging with attributes logger.WithField("user", "test-user").Error("An error occurred") -// Error level is sent as an error event to Sentry +// Sending an error level log to Sentry. logger.Errorf("oh no!") - -// Fatal level is sent as an error event to Sentry and terminates the application +// Fatal also sends an error level log to Sentry, while also terminating the current process. logger.Fatalf("can't continue...") ``` @@ -102,6 +88,7 @@ by using `sentrylogrus.NewLogHookFromClient()` and passing an already created `s send them to Sentry's structured logging system. #### NewLogHook + ```go logHook, err := sentrylogrus.NewLogHook( []logrus.Level{logrus.InfoLevel, logrus.WarnLevel}, @@ -114,6 +101,7 @@ logHook, err := sentrylogrus.NewLogHook( #### NewLogHookFromClient Use `NewLogHookFromClient` if you've already initialized the Sentry SDK. + ```go if err := sentry.Init(sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", @@ -132,46 +120,9 @@ if client != nil { } ``` -### EventHook - -You also have two ways to create a new `EventHook`. Either by using `sentrylogrus.NewEventHook()` and passing the `sentry.ClientOptions`, or -by using `sentrylogrus.NewEventFromClient()` and passing an already created `sentry.Client`. These hook captures log entries and -send them as events. This is helpful for error tracking and alerting. - -#### NewEventHook -```go -eventHook, err := sentrylogrus.NewEventHook( - []logrus.Level{logrus.ErrorLevel, logrus.FatalLevel, logrus.PanicLevel}, - sentry.ClientOptions{ - Dsn: "___PUBLIC_DSN___", - Debug: true, - AttachStacktrace: true, - }, -) -``` -#### NewEventHookFromClient - -Use `NewEventHookFromClient` if you've already initialized the Sentry SDK. -```go -if err := sentry.Init(sentry.ClientOptions{ - Dsn: "https://examplePublicKey@o0.ingest.sentry.io/0", -}); err != nil { - log.Fatalf("Sentry initialization failed: %v", err) -} -hub := sentry.CurrentHub() -client := hub.Client() -if client != nil { - eventHook := sentrylogrus.NewEventHookFromClient( - []logrus.Level{logrus.InfoLevel, logrus.WarnLevel}, - client, - ) -} else { - log.Fatalf("Sentrylogrus initialization failed: nil client") -} -``` - - When using both hooks, ensure you flush both of them before the application exits and register exit handlers for fatal logs to avoid losing pending events. + Logrus sends records as structured logs. To capture an error as an issue, call + `sentry.CaptureException` or `sentry.CaptureMessage` explicitly. - + diff --git a/docs/platforms/go/common/logs/slog.mdx b/docs/platforms/go/common/logs/slog.mdx index f0192cfe949fd8..4a1e9ab3ea8dcb 100644 --- a/docs/platforms/go/common/logs/slog.mdx +++ b/docs/platforms/go/common/logs/slog.mdx @@ -29,19 +29,16 @@ go get github.com/getsentry/sentry-go/slog `sentryslog` accepts a `sentryslog.Option` struct to control which records are sent to Sentry and how they're enriched before sending. -| Field | Type | Description | Default | -| ----------------- | ------------------------------------- | ----------------------------------------------------------- | ------------------------------------------------------------------------------------------------------- | -| `EventLevel` | `[]slog.Level` | Log levels to capture as Sentry events | `[]slog.Level{slog.LevelError, sentryslog.LevelFatal}` | -| `LogLevel` | `[]slog.Level` | Log levels to capture as Sentry log entries | `[]slog.Level{slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError, sentryslog.LevelFatal}` | -| `Hub` | `*sentry.Hub` | Hub to use when capturing events | Current hub | -| `Converter` | `Converter` | Custom converter for turning log records into Sentry events | `sentryslog.DefaultConverter` | -| `AttrFromContext` | `[]func(context.Context) []slog.Attr` | Functions that add attributes from the current context | None | -| `AddSource` | `bool` | Include file and line information in Sentry output | `false` | -| `ReplaceAttr` | `func([]string, slog.Attr) slog.Attr` | Rewrite or filter attributes before sending | None | +| Field | Type | Description | Default | +| ----------------- | ------------------------------------- | ------------------------------------------- | ------------------------------------------------------------------------------------------------------- | +| `LogLevel` | `[]slog.Level` | Log levels to capture as Sentry log entries | `[]slog.Level{slog.LevelDebug, slog.LevelInfo, slog.LevelWarn, slog.LevelError, sentryslog.LevelFatal}` | +| `AttrFromContext` | `[]func(context.Context) []slog.Attr` | Add attributes from the current context | None | +| `AddSource` | `bool` | Include source information in Sentry output | `false` | +| `ReplaceAttr` | `func([]string, slog.Attr) slog.Attr` | Rewrite or filter attributes before sending | None | ## Verify -This example sends `ERROR` records as events and `INFO`/`WARN` records as structured logs. +This example sends selected records as structured logs. ```go package main @@ -56,8 +53,7 @@ import ( func main() { ctx := context.Background() handler := sentryslog.Option{ - EventLevel: []slog.Level{slog.LevelError, sentryslog.LevelFatal}, - LogLevel: []slog.Level{slog.LevelInfo, slog.LevelWarn}, + LogLevel: []slog.Level{slog.LevelInfo, slog.LevelWarn, slog.LevelError}, AddSource: true, }.NewSentryHandler(ctx) diff --git a/docs/platforms/go/common/migration.mdx b/docs/platforms/go/common/migration.mdx index ed8de056209add..3cce44cfd83126 100644 --- a/docs/platforms/go/common/migration.mdx +++ b/docs/platforms/go/common/migration.mdx @@ -25,7 +25,6 @@ go get github.com/getsentry/sentry-go raven-go - ```go import "github.com/getsentry/raven-go" @@ -71,7 +70,6 @@ SetIncludePaths() sentry-go - ```go sentry.Init(sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", @@ -91,7 +89,6 @@ Available options: see [Configuration](/platforms/go/configuration/options/) sec By default, TLS uses the host's root CA set. If you don't have `ca-certificates` (which should be your go-to way of fixing the missing certificates issue) and want to use `gocertifi` instead, you can provide pre-loaded cert files as one of the options to `sentry.Init` call: - ```go package main @@ -362,11 +359,16 @@ sentry-go ```go // use `sentry.WithScope`, see "Context / Per-event Section" +import "github.com/getsentry/sentry-go/attribute" + path := "filename.ext" f, err := os.Open(path) if err != nil { sentry.WithScope(func(scope *sentry.Scope) { - scope.SetExtras(map[string]interface{}{"path": path, "cwd": os.Getwd()}) + scope.SetAttributes( + attribute.String("path", path), + attribute.String("cwd", os.Getwd()), + ) sentry.CaptureException(err) }) } diff --git a/docs/platforms/go/common/tracing/instrumentation/auto-instrumentation.mdx b/docs/platforms/go/common/tracing/instrumentation/auto-instrumentation.mdx index d608ce19e5fe56..8c391ad5f293f7 100644 --- a/docs/platforms/go/common/tracing/instrumentation/auto-instrumentation.mdx +++ b/docs/platforms/go/common/tracing/instrumentation/auto-instrumentation.mdx @@ -18,7 +18,8 @@ Sentry provides middleware for the following Go HTTP frameworks: | --------- | -------------------- | ------------------------------------------------ | | Gin | `sentry-go/gin` | [Gin guide](/platforms/go/guides/gin/) | | Echo | `sentry-go/echo` | [Echo guide](/platforms/go/guides/echo/) | -| Fiber | `sentry-go/fiber` | [Fiber guide](/platforms/go/guides/fiber/) | +| Fiber v2 | `sentry-go/fiber` | [Fiber guide](/platforms/go/guides/fiber/) | +| Fiber v3 | `sentry-go/fiberv3` | [Fiber v3 guide](/platforms/go/guides/fiberv3/) | | net/http | `sentry-go/http` | [net/http guide](/platforms/go/guides/http/) | | Iris | `sentry-go/iris` | [Iris guide](/platforms/go/guides/iris/) | | FastHTTP | `sentry-go/fasthttp` | [FastHTTP guide](/platforms/go/guides/fasthttp/) | diff --git a/docs/platforms/go/guides/echo/index.mdx b/docs/platforms/go/guides/echo/index.mdx index c25eeb67832796..8b7ae47d14d16b 100644 --- a/docs/platforms/go/guides/echo/index.mdx +++ b/docs/platforms/go/guides/echo/index.mdx @@ -105,7 +105,7 @@ app.Use(func(next echo.HandlerFunc) echo.HandlerFunc { app.GET("/", func(ctx *echo.Context) error { if hub := sentryecho.GetHubFromContext(ctx); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } diff --git a/docs/platforms/go/guides/fasthttp/index.mdx b/docs/platforms/go/guides/fasthttp/index.mdx index f804594e6d7c04..f5af8062fbb253 100644 --- a/docs/platforms/go/guides/fasthttp/index.mdx +++ b/docs/platforms/go/guides/fasthttp/index.mdx @@ -102,7 +102,7 @@ sentryHandler := sentryfasthttp.New(sentryfasthttp.Options{ defaultHandler := func(ctx *fasthttp.RequestCtx) { if hub := sentryfasthttp.GetHubFromContext(ctx); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } @@ -131,7 +131,6 @@ if err := fasthttp.ListenAndServe(":3000", sentryHandler.Handle(fastHTTPHandler) ### Accessing Context in `BeforeSend` callback - ```go sentry.Init(sentry.ClientOptions{ Dsn: "___PUBLIC_DSN___", diff --git a/docs/platforms/go/guides/fiber/index.mdx b/docs/platforms/go/guides/fiber/index.mdx index 228e9376e20e7f..e43e47e35965e9 100644 --- a/docs/platforms/go/guides/fiber/index.mdx +++ b/docs/platforms/go/guides/fiber/index.mdx @@ -100,7 +100,7 @@ sentryHandler := sentryfiber.New(sentryfiber.Options{ defaultHandler := func(ctx *fiber.Ctx) error { if hub := sentryfiber.GetHubFromContext(ctx); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } diff --git a/docs/platforms/go/guides/fiberv3/index.mdx b/docs/platforms/go/guides/fiberv3/index.mdx new file mode 100644 index 00000000000000..c304fad4692b7e --- /dev/null +++ b/docs/platforms/go/guides/fiberv3/index.mdx @@ -0,0 +1,148 @@ +--- +title: Fiber v3 +description: "Learn how to add Sentry instrumentation to programs using Fiber v3." +--- + +For a quick reference, see the [Fiber v3 example](https://github.com/getsentry/sentry-go/tree/master/_examples/fiber) in the Go SDK source code repository. + +[Go Dev-style API documentation](https://pkg.go.dev/github.com/getsentry/sentry-go/fiberv3) is also available. + + + Fiber v3 uses the `github.com/getsentry/sentry-go/fiberv3` package. For Fiber + v2, use the [`sentry-go/fiber` package](/platforms/go/guides/fiber/). + + +## Install + +```bash +go get github.com/getsentry/sentry-go +go get github.com/getsentry/sentry-go/fiberv3 +``` + + + +## Configure + +### Initialize the Sentry SDK + + + +### Options + +`sentryfiberv3` accepts a struct of `Options` that allows you to configure how the handler behaves. + +```go +// Repanic configures whether Sentry should repanic after recovery. Fiber v3 +// doesn't include its own Recovery handler, so set this according to how your +// application handles panics. +Repanic bool +// WaitForDelivery configures whether to block the request before continuing. +// Enable it when the application may exit before the event is delivered. +WaitForDelivery bool +// Timeout for the event delivery requests. +Timeout time.Duration +``` + + + +```go +sentryHandler := sentryfiberv3.New(sentryfiberv3.Options{ + // you can modify these options + Repanic: true, + WaitForDelivery: true, + Timeout: 5 * time.Second, +}) + +app := fiber.New() +app.Use(sentryHandler) +``` + +## Verify + +```go +app := fiber.New() + +app.Use(sentryfiberv3.New(sentryfiberv3.Options{ +// specify options here... +})) + +app.All("/", func(ctx fiber.Ctx) error { + // capturing an error intentionally to simulate usage + sentry.CaptureMessage("It works!") + + return ctx.SendStatus(fiber.StatusOK) +}) + +if err := app.Listen(":3000"); err != nil { + panic(err) +} +``` + +## Usage + +`sentryfiberv3` attaches an instance of `*sentry.Hub` to `fiber.Ctx`, which makes it available throughout the rest of the request's lifetime. +You can access it with `sentryfiberv3.GetHubFromContext()` in subsequent middleware and routes. +Use this hub instead of the global capture functions to keep data separated between requests. + + + +**Keep in mind that `*sentry.Hub` won't be available in middleware attached before `sentryfiberv3`!** + +```go +func enhanceSentryEvent(ctx fiber.Ctx) error { + if hub := sentryfiberv3.GetHubFromContext(ctx); hub != nil { + hub.Scope().SetTag("someRandomTag", "maybeYouNeedIt") + } + return ctx.Next() +} + +sentryHandler := sentryfiberv3.New(sentryfiberv3.Options{ + Repanic: true, + WaitForDelivery: true, +}) + +defaultHandler := func(ctx fiber.Ctx) error { + if hub := sentryfiberv3.GetHubFromContext(ctx); hub != nil { + hub.WithScope(func(scope *sentry.Scope) { + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) + hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") + }) + } + return ctx.SendStatus(fiber.StatusOK) +} + +fooHandler := func(ctx fiber.Ctx) error { + enhanceSentryEvent(ctx) + panic("y tho") +} + +app.Use(sentryHandler) +app.All("/foo", fooHandler) +app.All("/", defaultHandler) + +if err := app.Listen(":3000"); err != nil { + panic(err) +} +``` + +### Accessing Context in `BeforeSend` callback + +Fiber v3 passes a `fiber.Ctx` value in the request context rather than the `*fiber.Ctx` used by Fiber v2: + +```go +sentry.Init(sentry.ClientOptions{ + Dsn: "___PUBLIC_DSN___", + BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event { + if hint.Context != nil { + if ctx, ok := hint.Context.Value(sentry.RequestContextKey).(fiber.Ctx); ok { + fmt.Println(ctx.Hostname()) + } + } + return event + }, +}) +``` + +## Next Steps + +- Explore [practical guides](/guides/) on what to monitor, log, track, and investigate after setup diff --git a/docs/platforms/go/guides/gin/index.mdx b/docs/platforms/go/guides/gin/index.mdx index 208deb95052575..84b01135a1f1ff 100644 --- a/docs/platforms/go/guides/gin/index.mdx +++ b/docs/platforms/go/guides/gin/index.mdx @@ -99,7 +99,7 @@ app.Use(func(ctx *gin.Context) { app.GET("/", func(ctx *gin.Context) { if hub := sentrygin.GetHubFromContext(ctx); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } diff --git a/docs/platforms/go/guides/http/index.mdx b/docs/platforms/go/guides/http/index.mdx index b66cfe7817158d..c0f437a62aecac 100644 --- a/docs/platforms/go/guides/http/index.mdx +++ b/docs/platforms/go/guides/http/index.mdx @@ -92,7 +92,7 @@ type handler struct{} func (h *handler) ServeHTTP(rw http.ResponseWriter, r *http.Request) { if hub := sentry.GetHubFromContext(r.Context()); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } diff --git a/docs/platforms/go/guides/iris/index.mdx b/docs/platforms/go/guides/iris/index.mdx index 57a9dfdfb6c8fe..dbee2a6919710c 100644 --- a/docs/platforms/go/guides/iris/index.mdx +++ b/docs/platforms/go/guides/iris/index.mdx @@ -100,7 +100,7 @@ app.Use(func(ctx iris.Context) { app.Get("/", func(ctx iris.Context) { if hub := sentryiris.GetHubFromContext(ctx); hub != nil { hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) } diff --git a/docs/platforms/go/guides/negroni/index.mdx b/docs/platforms/go/guides/negroni/index.mdx index a2a02292415158..ff63ce5770f560 100644 --- a/docs/platforms/go/guides/negroni/index.mdx +++ b/docs/platforms/go/guides/negroni/index.mdx @@ -104,7 +104,7 @@ mux := http.NewServeMux() mux.HandleFunc("/", func(rw http.ResponseWriter, r *http.Request) { hub := sentry.GetHubFromContext(r.Context()) hub.WithScope(func(scope *sentry.Scope) { - scope.SetExtra("unwantedQuery", "someQueryDataMaybe") + scope.SetAttributes(attribute.String("unwantedQuery", "someQueryDataMaybe")) hub.CaptureMessage("User provided unwanted query string, but we recovered just fine") }) rw.WriteHeader(http.StatusOK) diff --git a/platform-includes/set-extra/go.mdx b/platform-includes/set-extra/go.mdx index 1709e9b4785b60..969f30a01b8afb 100644 --- a/platform-includes/set-extra/go.mdx +++ b/platform-includes/set-extra/go.mdx @@ -1,5 +1,7 @@ ```go +import "github.com/getsentry/sentry-go/attribute" + sentry.ConfigureScope(func(scope *sentry.Scope) { - scope.SetExtra("character.name", "Mighty Fighter") + scope.SetAttributes(attribute.String("character.name", "Mighty Fighter")) }) ```