MM-20951 Add sentry support to mattermost-server (#14405)

Этот коммит содержится в:
Eli Yukelzon
2020-05-21 16:13:37 +03:00
коммит произвёл GitHub
родитель 43e606173b
Коммит 008961ba2f
33 изменённых файлов: 4639 добавлений и 6 удалений

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 сгенерированный поставляемый Обычный файл
Просмотреть файл

@@ -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)
}
}
}