MM-20951 Add sentry support to mattermost-server (#14405)
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
43e606173b
Коммит
008961ba2f
135
vendor/github.com/getsentry/sentry-go/http/README.md
сгенерированный
поставляемый
Обычный файл
135
vendor/github.com/getsentry/sentry-go/http/README.md
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,135 @@
|
||||
<p align="center">
|
||||
<a href="https://sentry.io" target="_blank" align="center">
|
||||
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
|
||||
</a>
|
||||
<br />
|
||||
</p>
|
||||
|
||||
# Official Sentry net/http Handler for Sentry-go SDK
|
||||
|
||||
**Godoc:** https://godoc.org/github.com/getsentry/sentry-go/http
|
||||
|
||||
**Example:** https://github.com/getsentry/sentry-go/tree/master/example/http
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
go get github.com/getsentry/sentry-go/http
|
||||
```
|
||||
|
||||
```go
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||
)
|
||||
|
||||
// To initialize Sentry's handler, you need to initialize Sentry itself beforehand
|
||||
if err := sentry.Init(sentry.ClientOptions{
|
||||
Dsn: "your-public-dsn",
|
||||
}); err != nil {
|
||||
fmt.Printf("Sentry initialization failed: %v\n", err)
|
||||
}
|
||||
|
||||
// Create an instance of sentryhttp
|
||||
sentryHandler := sentryhttp.New(sentryhttp.Options{})
|
||||
|
||||
// Once it's done, you can setup routes and attach the handler as one of your middleware
|
||||
http.Handle("/", sentryHandler.Handle(&handler{}))
|
||||
http.HandleFunc("/foo", sentryHandler.HandleFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
panic("y tho")
|
||||
}))
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :3000")
|
||||
|
||||
// And run it
|
||||
if err := http.ListenAndServe(":3000", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
`sentryhttp` accepts a struct of `Options` that allows you to configure how the handler will behave.
|
||||
|
||||
Currently it respects 3 options:
|
||||
|
||||
```go
|
||||
// Whether Sentry should repanic after recovery, in most cases it should be set to true,
|
||||
// and you should gracefully handle http responses.
|
||||
Repanic bool
|
||||
// Whether you want to block the request before moving forward with the response.
|
||||
// Useful, when you want to restart the process after it panics.
|
||||
WaitForDelivery bool
|
||||
// Timeout for the event delivery requests.
|
||||
Timeout time.Duration
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
`sentryhttp` attaches an instance of `*sentry.Hub` (https://godoc.org/github.com/getsentry/sentry-go#Hub) to the request's context, which makes it available throughout the rest of the request's lifetime.
|
||||
You can access it by using the `sentry.GetHubFromContext()` method on the request itself in any of your proceeding middleware and routes.
|
||||
And it should be used instead of the global `sentry.CaptureMessage`, `sentry.CaptureException`, or any other calls, as it keeps the separation of data between the requests.
|
||||
|
||||
**Keep in mind that `*sentry.Hub` won't be available in middleware attached before to `sentryhttp`!**
|
||||
|
||||
```go
|
||||
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")
|
||||
hub.CaptureMessage("User provided unwanted query string, but we recovered just fine")
|
||||
})
|
||||
}
|
||||
rw.WriteHeader(http.StatusOK)
|
||||
}
|
||||
|
||||
func enhanceSentryEvent(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, r *http.Request) {
|
||||
if hub := sentry.GetHubFromContext(r.Context()); hub != nil {
|
||||
hub.Scope().SetTag("someRandomTag", "maybeYouNeedIt")
|
||||
}
|
||||
handler(rw, r)
|
||||
}
|
||||
}
|
||||
|
||||
// Later in the code
|
||||
|
||||
sentryHandler := sentryhttp.New(sentryhttp.Options{
|
||||
Repanic: true,
|
||||
})
|
||||
|
||||
http.Handle("/", sentryHandler.Handle(&handler{}))
|
||||
http.HandleFunc("/foo", sentryHandler.HandleFunc(
|
||||
enhanceSentryEvent(func(rw http.ResponseWriter, r *http.Request) {
|
||||
panic("y tho")
|
||||
}),
|
||||
))
|
||||
|
||||
fmt.Println("Listening and serving HTTP on :3000")
|
||||
|
||||
if err := http.ListenAndServe(":3000", nil); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
```
|
||||
|
||||
### Accessing Request in `BeforeSend` callback
|
||||
|
||||
```go
|
||||
sentry.Init(sentry.ClientOptions{
|
||||
Dsn: "your-public-dsn",
|
||||
BeforeSend: func(event *sentry.Event, hint *sentry.EventHint) *sentry.Event {
|
||||
if hint.Context != nil {
|
||||
if req, ok := hint.Context.Value(sentry.RequestContextKey).(*http.Request); ok {
|
||||
// You have access to the original Request here
|
||||
}
|
||||
}
|
||||
|
||||
return event
|
||||
},
|
||||
})
|
||||
```
|
||||
92
vendor/github.com/getsentry/sentry-go/http/sentryhttp.go
сгенерированный
поставляемый
Обычный файл
92
vendor/github.com/getsentry/sentry-go/http/sentryhttp.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,92 @@
|
||||
package sentryhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
type Handler struct {
|
||||
repanic bool
|
||||
waitForDelivery bool
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
// Repanic configures whether Sentry should repanic after recovery
|
||||
Repanic bool
|
||||
// WaitForDelivery indicates whether to wait until panic details have been
|
||||
// sent to Sentry before panicking or proceeding with a request.
|
||||
WaitForDelivery bool
|
||||
// Timeout for the event delivery requests.
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// New returns a struct that provides Handle and HandleFunc methods
|
||||
// that satisfy http.Handler and http.HandlerFunc interfaces.
|
||||
func New(options Options) *Handler {
|
||||
handler := Handler{
|
||||
repanic: false,
|
||||
timeout: time.Second * 2,
|
||||
waitForDelivery: false,
|
||||
}
|
||||
|
||||
if options.Repanic {
|
||||
handler.repanic = true
|
||||
}
|
||||
|
||||
if options.Timeout != 0 {
|
||||
handler.timeout = options.Timeout
|
||||
}
|
||||
|
||||
if options.WaitForDelivery {
|
||||
handler.waitForDelivery = true
|
||||
}
|
||||
|
||||
return &handler
|
||||
}
|
||||
|
||||
// Handle wraps http.Handler and recovers from caught panics.
|
||||
func (h *Handler) Handle(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
hub := sentry.CurrentHub().Clone()
|
||||
hub.Scope().SetRequest(r)
|
||||
ctx := sentry.SetHubOnContext(
|
||||
r.Context(),
|
||||
hub,
|
||||
)
|
||||
defer h.recoverWithSentry(hub, r)
|
||||
handler.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
}
|
||||
|
||||
// HandleFunc wraps http.HandleFunc and recovers from caught panics.
|
||||
func (h *Handler) HandleFunc(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return func(rw http.ResponseWriter, r *http.Request) {
|
||||
hub := sentry.CurrentHub().Clone()
|
||||
hub.Scope().SetRequest(r)
|
||||
ctx := sentry.SetHubOnContext(
|
||||
r.Context(),
|
||||
hub,
|
||||
)
|
||||
defer h.recoverWithSentry(hub, r)
|
||||
handler(rw, r.WithContext(ctx))
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) recoverWithSentry(hub *sentry.Hub, r *http.Request) {
|
||||
if err := recover(); err != nil {
|
||||
eventID := hub.RecoverWithContext(
|
||||
context.WithValue(r.Context(), sentry.RequestContextKey, r),
|
||||
err,
|
||||
)
|
||||
if eventID != nil && h.waitForDelivery {
|
||||
hub.Flush(h.timeout)
|
||||
}
|
||||
if h.repanic {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
Ссылка в новой задаче
Block a user