Skip to content

Commit

Permalink
docs: Go async delivery and goroutines hub (#1085)
Browse files Browse the repository at this point in the history
* docs: Create a note regarding default async events delivery in Go
* docs: Create documentation for scopes usage inside Goroutines
* Apply suggestions from code review
Co-Authored-By: Anton Ovchinnikov <[email protected]>
  • Loading branch information
kamilogorek authored Jul 1, 2019
1 parent 068ba2f commit 0bf42ca
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
1 change: 1 addition & 0 deletions __tests__/__snapshots__/documentation.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ Array [
"platforms/go/config/index.html",
"platforms/go/echo/index.html",
"platforms/go/gin/index.html",
"platforms/go/goroutines/index.html",
"platforms/go/http/index.html",
"platforms/go/index.html",
"platforms/go/integrations/index.html",
Expand Down
53 changes: 53 additions & 0 deletions src/collections/_documentation/platforms/go/goroutines.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: Goroutines
sidebar_order: 4
---

A goroutine is a lightweight thread managed by the Go runtime. Goroutines can run concurrently, and because of this, every goroutine has to keep track of its own Sentry-related data locally. Otherwise, there is a chance that you will override your data stored in the Scope. More on this in [Scopes and Hubs]({%- link _documentation/enriching-error-data/scopes.md -%}?platform={{ include.platform }}) section.

The easiest way to handle this, is to create a new `Hub` for every goroutine you start, however this would require you to rebind the current `Client` and handle `Scope` yourself. That is why we provide a helper method called `Clone`. It takes care of creating a `Hub`, cloning existing `Scope` and reassigning it alongside `Client` to newly create instance.

Once cloned, `Hub` is completly isolated and can be used safely inside concurrent call. However, instead of using globally exposed methods, they should be called directly on the `Hub`.

Here are two examples: one that is non-deterministic, would leak information between threads, and could trigger a concurrent-write panic; and one that is totally safe, and should be used instead.

```go
// Example of __INCORRECT__ use of scopes inside a Goroutines - DON'T USE IT!

go func() {
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("secretTag", "go#1")
})
sentry.CaptureMessage("Hello from Goroutine! #1")
}()

go func() {
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("secretTag", "go#2")
})
sentry.CaptureMessage("Hello from Goroutine! #2")
}()

// at this point both events can have either `go#1` tag or `go#2` tag or it can panic with concurrent writes. We'll never know.
```

```go
// Example of __CORRECT__ use of scopes inside a Goroutines

go func(localHub *sentry.Hub) {
// as goroutine argument
localHub.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("secretTag", "go#1")
})
localHub.CaptureMessage("Hello from Goroutine! #1")
}(sentry.CurrentHub().Clone())

go func() {
// or created locally
localHub := sentry.CurrentHub().Clone()
localHub.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTag("secretTag", "go#2")
})
localHub.CaptureMessage("Hello from Goroutine! #2")
}()
```
15 changes: 15 additions & 0 deletions src/collections/_documentation/platforms/go/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,12 +42,24 @@ To use `sentry-go`, you’ll need to import the `sentry-go` package and initiali

More on this in [Configuration]({%- link _documentation/platforms/go/config.md -%}) section.

## Usage {#usage}

{% capture __alert_content -%}
By default, Sentry Go SDK uses asynchronous transport, which in the code example below requires an explicit awaiting for event delivery to be finished using `sentry.Flush` method. It is necessary, because otherwise the program would not wait for the async HTTP calls to return a response, and exit the process immediately when it reached the end of the `main` function. It would not be required inside a running goroutine or if you would use `HTTPSyncTransport`, which you can read about in `Transports` section.
{%- endcapture -%}
{%- include components/alert.html
level="info"
title="Awaiting Event Delivery"
content=__alert_content
%}

```go
package main

import (
"fmt"
"os"
"time"

"github.com/getsentry/sentry-go"
)
Expand All @@ -64,9 +76,11 @@ func main() {
f, err := os.Open("filename.ext")
if err != nil {
sentry.CaptureException(err)
sentry.Flush(time.Second * 5)
}
}
```

<!-- ENDWIZARD -->

## Next Steps
Expand All @@ -77,6 +91,7 @@ For more detailed information about how to get the most out of `sentry-go` there
- [Error Reporting]({%- link _documentation/error-reporting/quickstart.md -%}?platform={{ include.platform }})
- [Enriching Error Data]({%- link _documentation/enriching-error-data/context.md -%}?platform={{ include.platform }})
- [Transports]({%- link _documentation/platforms/go/transports.md -%})
- [Goroutines]({%- link _documentation/platforms/go/goroutines.md -%})
- [Integrations]({%- link _documentation/platforms/go/integrations.md -%})
- [net/http]({%- link _documentation/platforms/go/http.md -%})
- [echo]({%- link _documentation/platforms/go/echo.md -%})
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Integrations
sidebar_order: 4
sidebar_order: 5
---

The sentry-go package currently comes with an integration for the native `net/http` package, `echo`, `gin`, `iris`, `martini` and `negroni` to make it easy to handle common scenarios.
Expand Down

0 comments on commit 0bf42ca

Please sign in to comment.