MM-31436: Upgrade dependencies (#16605)
* MM-31436: Upgrade dependencies Ran make update-dependencies https://mattermost.atlassian.net/browse/MM-31436 ```release-note NONE ``` * add missing dep * fix lru marshaling
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
09d2f698cc
Коммит
091659c8ad
8
vendor/github.com/getsentry/sentry-go/.golangci.yml
сгенерированный
поставляемый
8
vendor/github.com/getsentry/sentry-go/.golangci.yml
сгенерированный
поставляемый
@@ -39,6 +39,14 @@ issues:
|
||||
- path: _test\.go
|
||||
linters:
|
||||
- prealloc
|
||||
- path: _test\.go
|
||||
text: "G306:"
|
||||
linters:
|
||||
- gosec
|
||||
- path: errors_test\.go
|
||||
linters:
|
||||
- unused
|
||||
- path: http/example_test\.go
|
||||
linters:
|
||||
- errcheck
|
||||
- bodyclose
|
||||
|
||||
11
vendor/github.com/getsentry/sentry-go/.travis.yml
сгенерированный
поставляемый
11
vendor/github.com/getsentry/sentry-go/.travis.yml
сгенерированный
поставляемый
@@ -1,9 +1,9 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
- 1.13.x
|
||||
- 1.14.x
|
||||
- 1.15.x
|
||||
- master
|
||||
|
||||
env:
|
||||
@@ -33,6 +33,15 @@ before_install:
|
||||
# branch, since Travis clones only the target branch.
|
||||
- git fetch origin master:remotes/origin/master
|
||||
|
||||
install: |
|
||||
if [[ $GO111MODULE == off ]]; then
|
||||
# Iris is not supported in legacy GOPATH mode. We delete the source code
|
||||
# because otherwise lint, build, and test steps would fail.
|
||||
rm -vrf ./iris/ ./example/iris/
|
||||
go get -v -t ./...
|
||||
fi
|
||||
# go get is not required in Module mode
|
||||
|
||||
script:
|
||||
- golangci-lint run --new-from-rev=$(git merge-base origin/master HEAD)
|
||||
- go build ./...
|
||||
|
||||
35
vendor/github.com/getsentry/sentry-go/CHANGELOG.md
сгенерированный
поставляемый
35
vendor/github.com/getsentry/sentry-go/CHANGELOG.md
сгенерированный
поставляемый
@@ -1,5 +1,38 @@
|
||||
# Changelog
|
||||
|
||||
## v0.9.0
|
||||
|
||||
- feat: Initial tracing and performance monitoring support (#285)
|
||||
- doc: Revamp sentryhttp documentation (#304)
|
||||
- fix: Hub.PopScope never empties the scope stack (#300)
|
||||
- ref: Report Event.Timestamp in local time (#299)
|
||||
- ref: Report Breadcrumb.Timestamp in local time (#299)
|
||||
|
||||
_NOTE:_
|
||||
This version introduces support for [Sentry's Performance Monitoring](https://docs.sentry.io/platforms/go/performance/).
|
||||
The new tracing capabilities are beta, and we plan to expand them on future versions. Feedback is welcome, please open new issues on GitHub.
|
||||
The `sentryhttp` package got better API docs, an [updated usage example](https://github.com/getsentry/sentry-go/tree/master/example/http) and support for creating automatic transactions as part of Performance Monitoring.
|
||||
|
||||
## v0.8.0
|
||||
|
||||
- build: Bump required version of Iris (#296)
|
||||
- fix: avoid unnecessary allocation in Client.processEvent (#293)
|
||||
- doc: Remove deprecation of sentryhttp.HandleFunc (#284)
|
||||
- ref: Update sentryhttp example (#283)
|
||||
- doc: Improve documentation of sentryhttp package (#282)
|
||||
- doc: Clarify SampleRate documentation (#279)
|
||||
- fix: Remove RawStacktrace (#278)
|
||||
- docs: Add example of custom HTTP transport
|
||||
- ci: Test against go1.15, drop go1.12 support (#271)
|
||||
|
||||
_NOTE:_
|
||||
This version comes with a few updates. Some examples and documentation have been
|
||||
improved. We've bumped the supported version of the Iris framework to avoid
|
||||
LGPL-licensed modules in the module dependency graph.
|
||||
The `Exception.RawStacktrace` and `Thread.RawStacktrace` fields have been
|
||||
removed to conform to Sentry's ingestion protocol, only `Exception.Stacktrace`
|
||||
and `Thread.Stacktrace` should appear in user code.
|
||||
|
||||
## v0.7.0
|
||||
|
||||
- feat: Include original error when event cannot be encoded as JSON (#258)
|
||||
@@ -131,7 +164,7 @@ Please verify the usage of `sentry.Flush` in your code base.
|
||||
|
||||
## v0.3.0
|
||||
|
||||
- feat: Retry event marshalling without contextual data if the first pass fails
|
||||
- feat: Retry event marshaling without contextual data if the first pass fails
|
||||
- fix: Include `url.Parse` error in `DsnParseError`
|
||||
- fix: Make more `Scope` methods safe for concurrency
|
||||
- fix: Synchronize concurrent access to `Hub.client`
|
||||
|
||||
118
vendor/github.com/getsentry/sentry-go/README.md
сгенерированный
поставляемый
118
vendor/github.com/getsentry/sentry-go/README.md
сгенерированный
поставляемый
@@ -52,118 +52,39 @@ Check out the [list of released versions](https://pkg.go.dev/github.com/getsentr
|
||||
## Configuration
|
||||
|
||||
To use `sentry-go`, you’ll need to import the `sentry-go` package and initialize
|
||||
it with your DSN and other [options](https://godoc.org/github.com/getsentry/sentry-go#ClientOptions).
|
||||
it with your DSN and other [options](https://pkg.go.dev/github.com/getsentry/sentry-go#ClientOptions).
|
||||
|
||||
If not specified in the SDK initialization, the
|
||||
[DSN](https://docs.sentry.io/error-reporting/configuration/?platform=go#dsn),
|
||||
[Release](https://docs.sentry.io/workflow/releases/?platform=go) and
|
||||
[Environment](https://docs.sentry.io/enriching-error-data/environments/?platform=go)
|
||||
[DSN](https://docs.sentry.io/product/sentry-basics/dsn-explainer/),
|
||||
[Release](https://docs.sentry.io/product/releases/) and
|
||||
[Environment](https://docs.sentry.io/product/sentry-basics/environments/)
|
||||
are read from the environment variables `SENTRY_DSN`, `SENTRY_RELEASE` and
|
||||
`SENTRY_ENVIRONMENT`, respectively.
|
||||
|
||||
More on this in the [Configuration](https://docs.sentry.io/platforms/go/config/)
|
||||
section of the official Sentry documentation.
|
||||
More on this in the [Configuration section of the official Sentry Go SDK documentation](https://docs.sentry.io/platforms/go/configuration/).
|
||||
|
||||
## Usage
|
||||
|
||||
The SDK must be initialized with a call to `sentry.Init`. The default transport
|
||||
is asynchronous and thus most programs should call `sentry.Flush` to wait until
|
||||
buffered events are sent to Sentry right before the program terminates.
|
||||
The SDK supports reporting errors and tracking application performance.
|
||||
|
||||
Typically, `sentry.Init` is called in the beginning of `func main` and
|
||||
`sentry.Flush` is [deferred](https://golang.org/ref/spec#Defer_statements) right
|
||||
after.
|
||||
To get started, have a look at one of our [examples](example/):
|
||||
- [Basic error instrumentation](example/basic/main.go)
|
||||
- [Error and tracing for HTTP servers](example/http/main.go)
|
||||
|
||||
> Note that if the program terminates with a call to
|
||||
> [`os.Exit`](https://golang.org/pkg/os/#Exit), either directly or indirectly
|
||||
> via another function like `log.Fatal`, deferred functions are not run.
|
||||
>
|
||||
> In that case, and if it is important for you to report outstanding events
|
||||
> before terminating the program, arrange for `sentry.Flush` to be called before
|
||||
> the program terminates.
|
||||
|
||||
Example:
|
||||
|
||||
```go
|
||||
// This is an example program that makes an HTTP request and prints response
|
||||
// headers. Whenever a request fails, the error is reported to Sentry.
|
||||
//
|
||||
// Try it by running:
|
||||
//
|
||||
// go run main.go
|
||||
// go run main.go https://sentry.io
|
||||
// go run main.go bad-url
|
||||
//
|
||||
// To actually report events to Sentry, set the DSN either by editing the
|
||||
// appropriate line below or setting the environment variable SENTRY_DSN to
|
||||
// match the DSN of your Sentry project.
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatalf("usage: %s URL", os.Args[0])
|
||||
}
|
||||
|
||||
err := sentry.Init(sentry.ClientOptions{
|
||||
// Either set your DSN here or set the SENTRY_DSN environment variable.
|
||||
Dsn: "",
|
||||
// Enable printing of SDK debug messages.
|
||||
// Useful when getting started or trying to figure something out.
|
||||
Debug: true,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("sentry.Init: %s", err)
|
||||
}
|
||||
// Flush buffered events before the program terminates.
|
||||
// Set the timeout to the maximum duration the program can afford to wait.
|
||||
defer sentry.Flush(2 * time.Second)
|
||||
|
||||
resp, err := http.Get(os.Args[1])
|
||||
if err != nil {
|
||||
sentry.CaptureException(err)
|
||||
log.Printf("reported to Sentry: %s", err)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
for header, values := range resp.Header {
|
||||
for _, value := range values {
|
||||
fmt.Printf("%s=%s\n", header, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
For your convenience, this example is available at
|
||||
[`example/basic/main.go`](example/basic/main.go).
|
||||
There are also more examples in the
|
||||
[example](example) directory.
|
||||
We also provide a [complete API reference](https://pkg.go.dev/github.com/getsentry/sentry-go).
|
||||
|
||||
For more detailed information about how to get the most out of `sentry-go`,
|
||||
checkout the official documentation:
|
||||
|
||||
- [Configuration](https://docs.sentry.io/platforms/go/config)
|
||||
- [Error Reporting](https://docs.sentry.io/error-reporting/quickstart?platform=go)
|
||||
- [Enriching Error Data](https://docs.sentry.io/enriching-error-data/additional-data/?platform=go)
|
||||
- [Transports](https://docs.sentry.io/platforms/go/transports)
|
||||
- [Integrations](https://docs.sentry.io/platforms/go/integrations)
|
||||
- [net/http](https://docs.sentry.io/platforms/go/http)
|
||||
- [echo](https://docs.sentry.io/platforms/go/echo)
|
||||
- [fasthttp](https://docs.sentry.io/platforms/go/fasthttp)
|
||||
- [gin](https://docs.sentry.io/platforms/go/gin)
|
||||
- [iris](https://docs.sentry.io/platforms/go/iris)
|
||||
- [martini](https://docs.sentry.io/platforms/go/martini)
|
||||
- [negroni](https://docs.sentry.io/platforms/go/negroni)
|
||||
- [Sentry Go SDK documentation](https://docs.sentry.io/platforms/go/)
|
||||
- Guides:
|
||||
- [net/http](https://docs.sentry.io/platforms/go/guides/http/)
|
||||
- [echo](https://docs.sentry.io/platforms/go/guides/echo/)
|
||||
- [fasthttp](https://docs.sentry.io/platforms/go/guides/fasthttp/)
|
||||
- [gin](https://docs.sentry.io/platforms/go/guides/gin/)
|
||||
- [iris](https://docs.sentry.io/platforms/go/guides/iris/)
|
||||
- [martini](https://docs.sentry.io/platforms/go/guides/martini/)
|
||||
- [negroni](https://docs.sentry.io/platforms/go/guides/negroni/)
|
||||
|
||||
## Resources
|
||||
|
||||
@@ -177,7 +98,6 @@ checkout the official documentation:
|
||||
- [](http://stackoverflow.com/questions/tagged/sentry)
|
||||
- [](https://twitter.com/intent/follow?screen_name=getsentry)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
Licensed under
|
||||
|
||||
116
vendor/github.com/getsentry/sentry-go/client.go
сгенерированный
поставляемый
116
vendor/github.com/getsentry/sentry-go/client.go
сгенерированный
поставляемый
@@ -3,6 +3,7 @@ package sentry
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
@@ -14,6 +15,8 @@ import (
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go/internal/debug"
|
||||
)
|
||||
|
||||
// maxErrorDepth is the maximum number of errors reported in a chain of errors.
|
||||
@@ -88,7 +91,9 @@ var globalEventProcessors []EventProcessor
|
||||
// AddGlobalEventProcessor adds processor to the global list of event
|
||||
// processors. Global event processors apply to all events.
|
||||
//
|
||||
// Deprecated: Use Scope.AddEventProcessor or Client.AddEventProcessor instead.
|
||||
// AddGlobalEventProcessor is deprecated. Most users will prefer to initialize
|
||||
// the SDK with Init and provide a ClientOptions.BeforeSend function or use
|
||||
// Scope.AddEventProcessor instead.
|
||||
func AddGlobalEventProcessor(processor EventProcessor) {
|
||||
globalEventProcessors = append(globalEventProcessors, processor)
|
||||
}
|
||||
@@ -110,8 +115,15 @@ type ClientOptions struct {
|
||||
// Configures whether SDK should generate and attach stacktraces to pure
|
||||
// capture message calls.
|
||||
AttachStacktrace bool
|
||||
// The sample rate for event submission (0.0 - 1.0, defaults to 1.0).
|
||||
// The sample rate for event submission in the range [0.0, 1.0]. By default,
|
||||
// all events are sent. Thus, as a historical special case, the sample rate
|
||||
// 0.0 is treated as if it was 1.0. To drop all events, set the DSN to the
|
||||
// empty string.
|
||||
SampleRate float64
|
||||
// The sample rate for sampling traces in the range [0.0, 1.0].
|
||||
TracesSampleRate float64
|
||||
// Used to customize the sampling of traces, overrides TracesSampleRate.
|
||||
TracesSampler TracesSampler
|
||||
// List of regexp strings that will be used to match against event's message
|
||||
// and if applicable, caught errors type and value.
|
||||
// If the match is found, then a whole event will be dropped.
|
||||
@@ -157,17 +169,29 @@ type ClientOptions struct {
|
||||
}
|
||||
|
||||
// Client is the underlying processor that is used by the main API and Hub
|
||||
// instances.
|
||||
// instances. It must be created with NewClient.
|
||||
type Client struct {
|
||||
options ClientOptions
|
||||
dsn *Dsn
|
||||
eventProcessors []EventProcessor
|
||||
integrations []Integration
|
||||
Transport Transport
|
||||
// Transport is read-only. Replacing the transport of an existing client is
|
||||
// not supported, create a new client instead.
|
||||
Transport Transport
|
||||
}
|
||||
|
||||
// NewClient creates and returns an instance of Client configured using ClientOptions.
|
||||
// NewClient creates and returns an instance of Client configured using
|
||||
// ClientOptions.
|
||||
//
|
||||
// Most users will not create clients directly. Instead, initialize the SDK with
|
||||
// Init and use the package-level functions (for simple programs that run on a
|
||||
// single goroutine) or hub methods (for concurrent programs, for example web
|
||||
// servers).
|
||||
func NewClient(options ClientOptions) (*Client, error) {
|
||||
if options.TracesSampleRate != 0.0 && options.TracesSampler != nil {
|
||||
return nil, errors.New("TracesSampleRate and TracesSampler are mutually exclusive")
|
||||
}
|
||||
|
||||
if options.Debug {
|
||||
debugWriter := options.DebugWriter
|
||||
if debugWriter == nil {
|
||||
@@ -188,6 +212,13 @@ func NewClient(options ClientOptions) (*Client, error) {
|
||||
options.Environment = os.Getenv("SENTRY_ENVIRONMENT")
|
||||
}
|
||||
|
||||
if env := os.Getenv("SENTRYGODEBUG"); env == "dumphttp=1" {
|
||||
options.HTTPTransport = &debug.Transport{
|
||||
RoundTripper: http.DefaultTransport,
|
||||
Output: os.Stderr,
|
||||
}
|
||||
}
|
||||
|
||||
var dsn *Dsn
|
||||
if options.Dsn != "" {
|
||||
var err error
|
||||
@@ -209,17 +240,26 @@ func NewClient(options ClientOptions) (*Client, error) {
|
||||
}
|
||||
|
||||
func (client *Client) setupTransport() {
|
||||
transport := client.options.Transport
|
||||
opts := client.options
|
||||
transport := opts.Transport
|
||||
|
||||
if transport == nil {
|
||||
if client.options.Dsn == "" {
|
||||
if opts.Dsn == "" {
|
||||
transport = new(noopTransport)
|
||||
} else {
|
||||
transport = NewHTTPTransport()
|
||||
httpTransport := NewHTTPTransport()
|
||||
// When tracing is enabled, use larger buffer to
|
||||
// accommodate more concurrent events.
|
||||
// TODO(tracing): consider using separate buffers per
|
||||
// event type.
|
||||
if opts.TracesSampleRate != 0 || opts.TracesSampler != nil {
|
||||
httpTransport.BufferSize = 1000
|
||||
}
|
||||
transport = httpTransport
|
||||
}
|
||||
}
|
||||
|
||||
transport.Configure(client.options)
|
||||
transport.Configure(opts)
|
||||
client.Transport = transport
|
||||
}
|
||||
|
||||
@@ -246,7 +286,13 @@ func (client *Client) setupIntegrations() {
|
||||
}
|
||||
}
|
||||
|
||||
// AddEventProcessor adds an event processor to the client.
|
||||
// AddEventProcessor adds an event processor to the client. It must not be
|
||||
// called from concurrent goroutines. Most users will prefer to use
|
||||
// ClientOptions.BeforeSend or Scope.AddEventProcessor instead.
|
||||
//
|
||||
// Note that typical programs have only a single client created by Init and the
|
||||
// client is shared among multiple hubs, one per goroutine, such that adding an
|
||||
// event processor to the client affects all hubs that share the client.
|
||||
func (client *Client) AddEventProcessor(processor EventProcessor) {
|
||||
client.eventProcessors = append(client.eventProcessors, processor)
|
||||
}
|
||||
@@ -418,16 +464,31 @@ func (client *Client) processEvent(event *Event, hint *EventHint, scope EventMod
|
||||
|
||||
options := client.Options()
|
||||
|
||||
// TODO: Reconsider if its worth going away from default implementation
|
||||
// of other SDKs. In Go zero value (default) for float32 is 0.0,
|
||||
// which means that if someone uses ClientOptions{} struct directly
|
||||
// and we would not check for 0 here, we'd skip all events by default
|
||||
if options.SampleRate != 0.0 {
|
||||
randomFloat := rng.Float64()
|
||||
if randomFloat > options.SampleRate {
|
||||
Logger.Println("Event dropped due to SampleRate hit.")
|
||||
return nil
|
||||
}
|
||||
// The default error event sample rate for all SDKs is 1.0 (send all).
|
||||
//
|
||||
// In Go, the zero value (default) for float64 is 0.0, which means that
|
||||
// constructing a client with NewClient(ClientOptions{}), or, equivalently,
|
||||
// initializing the SDK with Init(ClientOptions{}) without an explicit
|
||||
// SampleRate would drop all events.
|
||||
//
|
||||
// To retain the desired default behavior, we exceptionally flip SampleRate
|
||||
// from 0.0 to 1.0 here. Setting the sample rate to 0.0 is not very useful
|
||||
// anyway, and the same end result can be achieved in many other ways like
|
||||
// not initializing the SDK, setting the DSN to the empty string or using an
|
||||
// event processor that always returns nil.
|
||||
//
|
||||
// An alternative API could be such that default options don't need to be
|
||||
// the same as Go's zero values, for example using the Functional Options
|
||||
// pattern. That would either require a breaking change if we want to reuse
|
||||
// the obvious NewClient name, or a new function as an alternative
|
||||
// constructor.
|
||||
if options.SampleRate == 0.0 {
|
||||
options.SampleRate = 1.0
|
||||
}
|
||||
|
||||
if !sample(options.SampleRate) {
|
||||
Logger.Println("Event dropped due to SampleRate hit.")
|
||||
return nil
|
||||
}
|
||||
|
||||
if event = client.prepareEvent(event, hint, scope); event == nil {
|
||||
@@ -436,11 +497,10 @@ func (client *Client) processEvent(event *Event, hint *EventHint, scope EventMod
|
||||
|
||||
// As per spec, transactions do not go through BeforeSend.
|
||||
if event.Type != transactionType && options.BeforeSend != nil {
|
||||
h := &EventHint{}
|
||||
if hint != nil {
|
||||
h = hint
|
||||
if hint == nil {
|
||||
hint = &EventHint{}
|
||||
}
|
||||
if event = options.BeforeSend(event, h); event == nil {
|
||||
if event = options.BeforeSend(event, hint); event == nil {
|
||||
Logger.Println("Event dropped due to BeforeSend callback.")
|
||||
return nil
|
||||
}
|
||||
@@ -457,7 +517,7 @@ func (client *Client) prepareEvent(event *Event, hint *EventHint, scope EventMod
|
||||
}
|
||||
|
||||
if event.Timestamp.IsZero() {
|
||||
event.Timestamp = time.Now().UTC()
|
||||
event.Timestamp = time.Now()
|
||||
}
|
||||
|
||||
if event.Level == "" {
|
||||
@@ -540,3 +600,9 @@ func (client Client) integrationAlreadyInstalled(name string) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// sample returns true with the given probability, which must be in the range
|
||||
// [0.0, 1.0].
|
||||
func sample(probability float64) bool {
|
||||
return rng.Float64() < probability
|
||||
}
|
||||
|
||||
25
vendor/github.com/getsentry/sentry-go/doc.go
сгенерированный
поставляемый
25
vendor/github.com/getsentry/sentry-go/doc.go
сгенерированный
поставляемый
@@ -1,6 +1,9 @@
|
||||
/*
|
||||
Package sentry is the official Sentry SDK for Go.
|
||||
|
||||
Use it to report errors and track application performance through distributed
|
||||
tracing.
|
||||
|
||||
For more information about Sentry and SDK features please have a look at the
|
||||
documentation site https://docs.sentry.io/platforms/go/.
|
||||
|
||||
@@ -17,6 +20,28 @@ Sentry project. This step is accomplished through a call to sentry.Init.
|
||||
A more detailed yet simple example is available at
|
||||
https://github.com/getsentry/sentry-go/blob/master/example/basic/main.go.
|
||||
|
||||
Error Reporting
|
||||
|
||||
The Capture* functions report messages and errors to Sentry.
|
||||
|
||||
sentry.CaptureMessage(...)
|
||||
sentry.CaptureException(...)
|
||||
sentry.CaptureEvent(...)
|
||||
|
||||
Use similarly named functions in the Hub for concurrent programs like web
|
||||
servers.
|
||||
|
||||
Performance Monitoring
|
||||
|
||||
You can use Sentry to monitor your application's performance. More information
|
||||
on the product page https://docs.sentry.io/product/performance/.
|
||||
|
||||
The StartSpan function creates new spans.
|
||||
|
||||
span := sentry.StartSpan(ctx, "operation")
|
||||
...
|
||||
span.Finish()
|
||||
|
||||
Integrations
|
||||
|
||||
The SDK has support for several Go frameworks, available as subpackages.
|
||||
|
||||
5
vendor/github.com/getsentry/sentry-go/dsn.go
сгенерированный
поставляемый
5
vendor/github.com/getsentry/sentry-go/dsn.go
сгенерированный
поставляемый
@@ -48,8 +48,9 @@ type Dsn struct {
|
||||
projectID int
|
||||
}
|
||||
|
||||
// NewDsn creates an instance of Dsn by parsing provided url in a string format.
|
||||
// If Dsn is not set the client is effectively disabled.
|
||||
// NewDsn creates a Dsn by parsing rawURL. Most users will never call this
|
||||
// function directly. It is provided for use in custom Transport
|
||||
// implementations.
|
||||
func NewDsn(rawURL string) (*Dsn, error) {
|
||||
// Parse
|
||||
parsedURL, err := url.Parse(rawURL)
|
||||
|
||||
5
vendor/github.com/getsentry/sentry-go/go.mod
сгенерированный
поставляемый
5
vendor/github.com/getsentry/sentry-go/go.mod
сгенерированный
поставляемый
@@ -1,6 +1,6 @@
|
||||
module github.com/getsentry/sentry-go
|
||||
|
||||
go 1.12
|
||||
go 1.13
|
||||
|
||||
require (
|
||||
github.com/ajg/form v1.5.1 // indirect
|
||||
@@ -13,7 +13,7 @@ require (
|
||||
github.com/google/go-querystring v1.0.0 // indirect
|
||||
github.com/imkira/go-interpol v1.1.0 // indirect
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 // indirect
|
||||
github.com/kataras/iris/v12 v12.0.1
|
||||
github.com/kataras/iris/v12 v12.1.8
|
||||
github.com/labstack/echo/v4 v4.1.11
|
||||
github.com/moul/http2curl v1.0.0 // indirect
|
||||
github.com/onsi/ginkgo v1.10.3 // indirect
|
||||
@@ -21,6 +21,7 @@ require (
|
||||
github.com/pingcap/errors v0.11.4
|
||||
github.com/pkg/errors v0.8.1
|
||||
github.com/sergi/go-diff v1.0.0 // indirect
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
github.com/ugorji/go v1.1.7 // indirect
|
||||
github.com/urfave/negroni v1.0.0
|
||||
|
||||
75
vendor/github.com/getsentry/sentry-go/go.sum
сгенерированный
поставляемый
75
vendor/github.com/getsentry/sentry-go/go.sum
сгенерированный
поставляемый
@@ -1,14 +1,12 @@
|
||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a h1:3SgJcK9l5uPdBC/X17wanyJAMxM33+4ZhEIV96MIH8U=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20170127035650-74b38d55f37a/go.mod h1:EFZQ978U7x8IRnstaskI3IysnWY5Ao3QgZUKOXlsAdw=
|
||||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible h1:rZgFj+Gtf3NMi/U5FvCvhzaxzW/TaPYgUYx3bAPz9DE=
|
||||
github.com/CloudyKit/jet v2.1.3-0.20180809161101-62edd43e4f88+incompatible/go.mod h1:HPYO+50pSWkPoj9Q/eq0aRGByCL6ScRlUmiEX5Zgm+w=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
|
||||
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
|
||||
github.com/CloudyKit/jet/v3 v3.0.0 h1:1PwO5w5VCtlUUl+KTOBsTGZlhjWkcybsGaAau52tOy8=
|
||||
github.com/CloudyKit/jet/v3 v3.0.0/go.mod h1:HKQPgSJmdK8hdoAbKUUWajkHyHo4RaU5rMdUywE7VMo=
|
||||
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
|
||||
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
|
||||
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7 h1:mreN1m/5VJ/Zc3b4pzj9qU6D9SRQ6Vm+3KfI328t3S8=
|
||||
github.com/Joker/jade v1.0.1-0.20190614124447-d475f43051e7/go.mod h1:6E6s8o2AE4KhCrqr6GRJjdC/gNfTdxkIXvuGZZda2VM=
|
||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398 h1:WDC6ySpJzbxGWFh4aMxFFC28wwGp5pEuoTtvA4q/qQ4=
|
||||
github.com/Shopify/goreferrer v0.0.0-20181106222321-ec9c9a553398/go.mod h1:a1uqRtAwp2Xwc6WNPJEufxJ7fx3npB4UV/JOLmbu5I0=
|
||||
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
|
||||
@@ -37,8 +35,6 @@ github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072 h1:Dddq
|
||||
github.com/fasthttp-contrib/websocket v0.0.0-20160511215533-1f3b11f56072/go.mod h1:duJ4Jxv5lDcvg4QuQr0oowTf7dz4/CR8NtyCooz9HL8=
|
||||
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
|
||||
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
|
||||
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4 h1:GY1+t5Dr9OKADM64SYnQjw/w99HMYvQ0A8/JoUkxVmc=
|
||||
github.com/flosch/pongo2 v0.0.0-20190707114632-bbf5a6c351f4/go.mod h1:T9YF2M40nIgbVgp3rreNmTged+9HrbNTIQf1PsaIiTA=
|
||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/gavv/httpexpect v2.0.0+incompatible h1:1X9kcRshkSKEjNJJxX9Y9mQ5BRfbxU5kORdjhlA1yX8=
|
||||
@@ -64,10 +60,11 @@ github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM=
|
||||
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
@@ -78,31 +75,32 @@ github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANyt
|
||||
github.com/iris-contrib/blackfriday v2.0.0+incompatible h1:o5sHQHHm0ToHUlAJSTjW9UWicjJSDDauOOQ2AHuIVp4=
|
||||
github.com/iris-contrib/blackfriday v2.0.0+incompatible/go.mod h1:UzZ2bDEoaSGPbkg6SAB4att1aAwTmVIx/5gCVqeyUdI=
|
||||
github.com/iris-contrib/go.uuid v2.0.0+incompatible/go.mod h1:iz2lgM/1UnEf1kP0L/+fafWORmlnuysV2EMP8MW+qe0=
|
||||
github.com/iris-contrib/i18n v0.0.0-20171121225848-987a633949d0/go.mod h1:pMCz62A0xJL6I+umB2YTlFRwWXaDFA0jy+5HzGiJjqI=
|
||||
github.com/iris-contrib/jade v1.1.3 h1:p7J/50I0cjo0wq/VWVCDFd8taPJbuFC+bq23SniRFX0=
|
||||
github.com/iris-contrib/jade v1.1.3/go.mod h1:H/geBymxJhShH5kecoiOCSssPX7QWYH7UaeZTSWddIk=
|
||||
github.com/iris-contrib/pongo2 v0.0.1 h1:zGP7pW51oi5eQZMIlGA3I+FHY9/HOQWDB+572yin0to=
|
||||
github.com/iris-contrib/pongo2 v0.0.1/go.mod h1:Ssh+00+3GAZqSQb30AvBRNxBx7rf0GqwkjqxNd0u65g=
|
||||
github.com/iris-contrib/schema v0.0.1 h1:10g/WnoRR+U+XXHWKBHeNy/+tZmM2kcAVGLOsz+yaDA=
|
||||
github.com/iris-contrib/schema v0.0.1/go.mod h1:urYA3uvUNG1TIIjOSCzHr9/LmbQo8LrOcOqfqxa4hXw=
|
||||
github.com/json-iterator/go v1.1.6 h1:MrUvLMLTMxbqFJ9kzlvat/rYZqZnW3u4wkLzWTaFwKs=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 h1:rhqTjzJlm7EbkELJDKMTU7udov+Se0xZkWmugr6zGok=
|
||||
github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5/go.mod h1:W54LbzXuIE0boCoNJfwqpmkKJ1O4TCTZMetAt6jGk7Q=
|
||||
github.com/juju/loggo v0.0.0-20180524022052-584905176618 h1:MK144iBQF9hTSwBW/9eJm034bVoG30IshVm688T2hi8=
|
||||
github.com/juju/loggo v0.0.0-20180524022052-584905176618/go.mod h1:vgyd7OREkbtVEN/8IXZe5Ooef3LQePvuBm9UWj6ZL8U=
|
||||
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073 h1:WQM1NildKThwdP7qWrNAFGzp4ijNLw8RlgENkaI4MJs=
|
||||
github.com/juju/testing v0.0.0-20180920084828-472a3e8b2073/go.mod h1:63prj8cnj0tU0S9OHjGJn+b1h0ZghCndfnbQolrYTwA=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88 h1:uC1QfSlInpQF+M0ao65imhwqKnz3Q2z/d8PWZRMQvDM=
|
||||
github.com/k0kubun/colorstring v0.0.0-20150214042306-9440f1994b88/go.mod h1:3w7q1U84EfirKl04SVQ/s7nPm1ZPhiXd34z40TNz36k=
|
||||
github.com/kataras/golog v0.0.9 h1:J7Dl82843nbKQDrQM/abbNJZvQjS6PfmkkffhOTXEpM=
|
||||
github.com/kataras/golog v0.0.9/go.mod h1:12HJgwBIZFNGL0EJnMRhmvGA0PQGx8VFwrZtM4CqbAk=
|
||||
github.com/kataras/iris/v12 v12.0.1 h1:Wo5S7GMWv5OAzJmvFTvss/C4TS1W0uo6LkDlSymT4rM=
|
||||
github.com/kataras/iris/v12 v12.0.1/go.mod h1:udK4vLQKkdDqMGJJVd/msuMtN6hpYJhg/lSzuxjhO+U=
|
||||
github.com/kataras/neffos v0.0.10/go.mod h1:ZYmJC07hQPW67eKuzlfY7SO3bC0mw83A3j6im82hfqw=
|
||||
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d h1:V5Rs9ztEWdp58oayPq/ulmlqJJZeJP6pP79uP3qjcao=
|
||||
github.com/kataras/pio v0.0.0-20190103105442-ea782b38602d/go.mod h1:NV88laa9UiiDuX9AhMbDPkGYSPugBOV6yTZB1l2K9Z0=
|
||||
github.com/kataras/golog v0.0.10 h1:vRDRUmwacco/pmBAm8geLn8rHEdc+9Z4NAr5Sh7TG/4=
|
||||
github.com/kataras/golog v0.0.10/go.mod h1:yJ8YKCmyL+nWjERB90Qwn+bdyBZsaQwU3bTVFgkFIp8=
|
||||
github.com/kataras/iris/v12 v12.1.8 h1:O3gJasjm7ZxpxwTH8tApZsvf274scSGQAUpNe47c37U=
|
||||
github.com/kataras/iris/v12 v12.1.8/go.mod h1:LMYy4VlP67TQ3Zgriz8RE2h2kMZV2SgMYbq3UhfoFmE=
|
||||
github.com/kataras/neffos v0.0.14/go.mod h1:8lqADm8PnbeFfL7CLXh1WHw53dG27MC3pgi2R1rmoTE=
|
||||
github.com/kataras/pio v0.0.2 h1:6NAi+uPJ/Zuid6mrAKlgpbI11/zK/lV4B2rxWaJN98Y=
|
||||
github.com/kataras/pio v0.0.2/go.mod h1:hAoW0t9UmXi4R5Oyq5Z4irTbaTsOemSrDGUtaTl7Dro=
|
||||
github.com/kataras/sitemap v0.0.5 h1:4HCONX5RLgVy6G4RkYOV3vKNcma9p236LdGOipJsaFE=
|
||||
github.com/kataras/sitemap v0.0.5/go.mod h1:KY2eugMKiPwsJgx7+U103YZehfvNGOXURubcGyk0Bz8=
|
||||
github.com/klauspost/compress v1.8.2/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.0 h1:GhthINjveNZAdFUD8QoQYfjxnOONZgztK/Yr6M23UTY=
|
||||
github.com/klauspost/compress v1.9.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/compress v1.9.7 h1:hYW1gP94JUmAhBtJ+LNz5My+gBobDxPR1iVuKug26aA=
|
||||
github.com/klauspost/compress v1.9.7/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||
github.com/klauspost/cpuid v1.2.1/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek=
|
||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
@@ -121,20 +119,22 @@ github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
||||
github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/goveralls v0.0.2/go.mod h1:8d1ZMHsd7fW6IRPKQh46F2WRpyib5/X4FOpevwGNQEw=
|
||||
github.com/mediocregopher/mediocre-go-lib v0.0.0-20181029021733-cb65787f37ed/go.mod h1:dSsfyI2zABAdhcbvkXqgxOxrCsbYeHCPgrZkku60dSg=
|
||||
github.com/mediocregopher/radix/v3 v3.3.0/go.mod h1:EmfVyvspXz1uZEyPBMyGK+kjWiKQGvsUt6O3Pj+LDCQ=
|
||||
github.com/mediocregopher/radix/v3 v3.4.2/go.mod h1:8FL3F6UQRXHXIBSPUs5h0RybMF8i4n7wVopoX3x7Bv8=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2 h1:5lPfLTTAvAbtS0VqT+94yOtFnGfUWYyx0+iToC3Os3s=
|
||||
github.com/microcosm-cc/bluemonday v1.0.2/go.mod h1:iVP4YcDBq+n/5fb23BhYFvIMq/leAFZyRl6bYmGDlGc=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/moul/http2curl v1.0.0 h1:dRMWoAtb+ePxMlLkrCbAqh4TlPHXvoGUSQ323/9Zahs=
|
||||
github.com/moul/http2curl v1.0.0/go.mod h1:8UbvGypXm98wA/IqH45anm5Y2Z6ep6O31QGOAZ3H0fQ=
|
||||
github.com/nats-io/nats.go v1.8.1/go.mod h1:BrFz9vVn0fU3AcH9Vn4Kd7W0NpJ651tD5omQ3M8LwxM=
|
||||
github.com/nats-io/nkeys v0.0.2/go.mod h1:dab7URMsZm6Z/jp9Z5UGa87Uutgc2mVpXLC4B7TDb/4=
|
||||
github.com/nats-io/jwt v0.3.0/go.mod h1:fRYCDE99xlTsqUzISS1Bi75UBJ6ljOJQOAAu5VglpSg=
|
||||
github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzEE/Zbp4w=
|
||||
github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w=
|
||||
github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
|
||||
@@ -151,6 +151,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible h1:j1Wcmh8OrK4Q7GXY+V7SVSY8nUWQxHW5TkBe7YUl+2s=
|
||||
github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
|
||||
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
|
||||
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
|
||||
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
@@ -205,6 +207,8 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4 h1:HuIa8hRrWRSrqYzx1qI49NNxhdi2PrY7gxVSq1JjLDc=
|
||||
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876 h1:sKJQZMuxjOAR/Uo2LBfU90onWEf1dF4C+0hPJCc9Mpc=
|
||||
golang.org/x/crypto v0.0.0-20191227163750-53104e6ec876/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -214,7 +218,10 @@ golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297 h1:k7pJ2yAPLPgbskkFdhRCsA77k2fySZ1zf2zCjvQCiIM=
|
||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553 h1:efeOvDhwQ29Dj3SdAV/MJf8oukgn+8D8WgaCaRMchF8=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -225,9 +232,13 @@ golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO
|
||||
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181221001348-537d06c36207/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190327201419-c70d86f8b7cf/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
@@ -238,6 +249,8 @@ gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXa
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ=
|
||||
gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y=
|
||||
gopkg.in/ini.v1 v1.51.1 h1:GyboHr4UqMiLUybYjd22ZjQIKEJEpgtLXtuGbR21Oho=
|
||||
gopkg.in/ini.v1 v1.51.1/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce h1:xcEWjVhvbDy+nHP67nPDDpbYrY+ILlfndk4bRioVHaU=
|
||||
gopkg.in/mgo.v2 v2.0.0-20180705113604-9856a29383ce/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA=
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
||||
@@ -246,3 +259,5 @@ gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4 h1:/eiJrUcujPVeJ3xlSWaiNi3uSVmDGBK1pDHUHAnao1I=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2 h1:XZx7nhd5GMaZpmDaEHFVafUZC7ya0fuo7cSJ3UCKYmM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20191120175047-4206685974f2/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
|
||||
90
vendor/github.com/getsentry/sentry-go/http/sentryhttp.go
сгенерированный
поставляемый
90
vendor/github.com/getsentry/sentry-go/http/sentryhttp.go
сгенерированный
поставляемый
@@ -1,75 +1,107 @@
|
||||
// Package sentryhttp provides Sentry integration for servers based on the
|
||||
// net/http package.
|
||||
package sentryhttp
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/getsentry/sentry-go"
|
||||
)
|
||||
|
||||
// A Handler is an HTTP middleware factory that provides integration with
|
||||
// Sentry.
|
||||
type Handler struct {
|
||||
repanic bool
|
||||
waitForDelivery bool
|
||||
timeout time.Duration
|
||||
}
|
||||
|
||||
// Options configure a Handler.
|
||||
type Options struct {
|
||||
// Repanic configures whether Sentry should repanic after recovery
|
||||
// Repanic configures whether to panic again after recovering from a panic.
|
||||
// Use this option if you have other panic handlers or want the default
|
||||
// behavior from Go's http package, as documented in
|
||||
// https://golang.org/pkg/net/http/#Handler.
|
||||
Repanic bool
|
||||
// WaitForDelivery indicates whether to wait until panic details have been
|
||||
// sent to Sentry before panicking or proceeding with a request.
|
||||
// WaitForDelivery indicates, in case of a panic, whether to block the
|
||||
// current goroutine and wait until the panic event has been reported to
|
||||
// Sentry before repanicking or resuming normal execution.
|
||||
//
|
||||
// This option is normally not needed. Unless you need different behaviors
|
||||
// for different HTTP handlers, configure the SDK to use the
|
||||
// HTTPSyncTransport instead.
|
||||
//
|
||||
// Waiting (or using HTTPSyncTransport) is useful when the web server runs
|
||||
// in an environment that interrupts execution at the end of a request flow,
|
||||
// like modern serverless platforms.
|
||||
WaitForDelivery bool
|
||||
// Timeout for the event delivery requests.
|
||||
// Timeout for the delivery of panic events. Defaults to 2s. Only relevant
|
||||
// when WaitForDelivery is true.
|
||||
//
|
||||
// If the timeout is reached, the current goroutine is no longer blocked
|
||||
// waiting, but the delivery is not canceled.
|
||||
Timeout time.Duration
|
||||
}
|
||||
|
||||
// New returns a struct that provides Handle and HandleFunc methods
|
||||
// that satisfy http.Handler and http.HandlerFunc interfaces.
|
||||
// New returns a new Handler. Use the Handle and HandleFunc methods to wrap
|
||||
// existing HTTP handlers.
|
||||
func New(options Options) *Handler {
|
||||
handler := Handler{
|
||||
repanic: false,
|
||||
timeout: time.Second * 2,
|
||||
waitForDelivery: false,
|
||||
timeout := options.Timeout
|
||||
if timeout == 0 {
|
||||
timeout = 2 * time.Second
|
||||
}
|
||||
|
||||
if options.Repanic {
|
||||
handler.repanic = true
|
||||
return &Handler{
|
||||
repanic: options.Repanic,
|
||||
timeout: timeout,
|
||||
waitForDelivery: options.WaitForDelivery,
|
||||
}
|
||||
|
||||
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.
|
||||
// Handle works as a middleware that wraps an existing http.Handler. A wrapped
|
||||
// handler will recover from and report panics to Sentry, and provide access to
|
||||
// a request-specific hub to report messages and errors.
|
||||
func (h *Handler) Handle(handler http.Handler) http.Handler {
|
||||
return h.handle(handler)
|
||||
}
|
||||
|
||||
// Deprecated: Use the Handle method instead.
|
||||
// HandleFunc is like Handle, but with a handler function parameter for cases
|
||||
// where that is convenient. In particular, use it to wrap a handler function
|
||||
// literal.
|
||||
//
|
||||
// http.Handle(pattern, h.HandleFunc(func (w http.ResponseWriter, r *http.Request) {
|
||||
// // handler code here
|
||||
// }))
|
||||
func (h *Handler) HandleFunc(handler http.HandlerFunc) http.HandlerFunc {
|
||||
return h.handle(handler)
|
||||
}
|
||||
|
||||
func (h *Handler) handle(handler http.Handler) http.HandlerFunc {
|
||||
return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
hub := sentry.GetHubFromContext(ctx)
|
||||
if hub == nil {
|
||||
hub = sentry.CurrentHub().Clone()
|
||||
ctx = sentry.SetHubOnContext(ctx, hub)
|
||||
}
|
||||
span := sentry.StartSpan(ctx, "http.server",
|
||||
sentry.TransactionName(fmt.Sprintf("%s %s", r.Method, r.URL.Path)),
|
||||
sentry.ContinueFromRequest(r),
|
||||
)
|
||||
defer span.Finish()
|
||||
// TODO(tracing): if the next handler.ServeHTTP panics, store
|
||||
// information on the transaction accordingly (status, tag,
|
||||
// level?, ...).
|
||||
r = r.WithContext(span.Context())
|
||||
hub.Scope().SetRequest(r)
|
||||
ctx = sentry.SetHubOnContext(ctx, hub)
|
||||
defer h.recoverWithSentry(hub, r)
|
||||
handler.ServeHTTP(rw, r.WithContext(ctx))
|
||||
})
|
||||
// TODO(tracing): use custom response writer to intercept
|
||||
// response. Use HTTP status to add tag to transaction; set span
|
||||
// status.
|
||||
handler.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) recoverWithSentry(hub *sentry.Hub, r *http.Request) {
|
||||
|
||||
53
vendor/github.com/getsentry/sentry-go/hub.go
сгенерированный
поставляемый
53
vendor/github.com/getsentry/sentry-go/hub.go
сгенерированный
поставляемый
@@ -92,30 +92,21 @@ func (hub *Hub) LastEventID() EventID {
|
||||
return hub.lastEventID
|
||||
}
|
||||
|
||||
// stackTop returns the top layer of the hub stack. Valid hubs always have at
|
||||
// least one layer, therefore stackTop always return a non-nil pointer.
|
||||
func (hub *Hub) stackTop() *layer {
|
||||
hub.mu.RLock()
|
||||
defer hub.mu.RUnlock()
|
||||
|
||||
stack := hub.stack
|
||||
if stack == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
stackLen := len(*stack)
|
||||
if stackLen == 0 {
|
||||
return nil
|
||||
}
|
||||
top := (*stack)[stackLen-1]
|
||||
|
||||
return top
|
||||
}
|
||||
|
||||
// Clone returns a copy of the current Hub with top-most scope and client copied over.
|
||||
func (hub *Hub) Clone() *Hub {
|
||||
top := hub.stackTop()
|
||||
if top == nil {
|
||||
return nil
|
||||
}
|
||||
scope := top.scope
|
||||
if scope != nil {
|
||||
scope = scope.Clone()
|
||||
@@ -126,18 +117,12 @@ func (hub *Hub) Clone() *Hub {
|
||||
// Scope returns top-level Scope of the current Hub or nil if no Scope is bound.
|
||||
func (hub *Hub) Scope() *Scope {
|
||||
top := hub.stackTop()
|
||||
if top == nil {
|
||||
return nil
|
||||
}
|
||||
return top.scope
|
||||
}
|
||||
|
||||
// Client returns top-level Client of the current Hub or nil if no Client is bound.
|
||||
func (hub *Hub) Client() *Client {
|
||||
top := hub.stackTop()
|
||||
if top == nil {
|
||||
return nil
|
||||
}
|
||||
return top.Client()
|
||||
}
|
||||
|
||||
@@ -145,13 +130,8 @@ func (hub *Hub) Client() *Client {
|
||||
func (hub *Hub) PushScope() *Scope {
|
||||
top := hub.stackTop()
|
||||
|
||||
var client *Client
|
||||
if top != nil {
|
||||
client = top.Client()
|
||||
}
|
||||
|
||||
var scope *Scope
|
||||
if top != nil && top.scope != nil {
|
||||
if top.scope != nil {
|
||||
scope = top.scope.Clone()
|
||||
} else {
|
||||
scope = NewScope()
|
||||
@@ -161,21 +141,29 @@ func (hub *Hub) PushScope() *Scope {
|
||||
defer hub.mu.Unlock()
|
||||
|
||||
*hub.stack = append(*hub.stack, &layer{
|
||||
client: client,
|
||||
client: top.Client(),
|
||||
scope: scope,
|
||||
})
|
||||
|
||||
return scope
|
||||
}
|
||||
|
||||
// PopScope pops the most recent scope for the current Hub.
|
||||
// PopScope drops the most recent scope.
|
||||
//
|
||||
// Calls to PopScope must be coordinated with PushScope. For most cases, using
|
||||
// WithScope should be more convenient.
|
||||
//
|
||||
// Calls to PopScope that do not match previous calls to PushScope are silently
|
||||
// ignored.
|
||||
func (hub *Hub) PopScope() {
|
||||
hub.mu.Lock()
|
||||
defer hub.mu.Unlock()
|
||||
|
||||
stack := *hub.stack
|
||||
stackLen := len(stack)
|
||||
if stackLen > 0 {
|
||||
if stackLen > 1 {
|
||||
// Never pop the last item off the stack, the stack should always have
|
||||
// at least one item.
|
||||
*hub.stack = stack[0 : stackLen-1]
|
||||
}
|
||||
}
|
||||
@@ -183,9 +171,7 @@ func (hub *Hub) PopScope() {
|
||||
// BindClient binds a new Client for the current Hub.
|
||||
func (hub *Hub) BindClient(client *Client) {
|
||||
top := hub.stackTop()
|
||||
if top != nil {
|
||||
top.SetClient(client)
|
||||
}
|
||||
top.SetClient(client)
|
||||
}
|
||||
|
||||
// WithScope runs f in an isolated temporary scope.
|
||||
@@ -381,6 +367,15 @@ func GetHubFromContext(ctx context.Context) *Hub {
|
||||
return nil
|
||||
}
|
||||
|
||||
// hubFromContext returns either a hub stored in the context or the current hub.
|
||||
// The return value is guaranteed to be non-nil, unlike GetHubFromContext.
|
||||
func hubFromContext(ctx context.Context) *Hub {
|
||||
if hub, ok := ctx.Value(HubContextKey).(*Hub); ok {
|
||||
return hub
|
||||
}
|
||||
return currentHub
|
||||
}
|
||||
|
||||
// SetHubOnContext stores given Hub instance on the Context struct and returns a new Context.
|
||||
func SetHubOnContext(ctx context.Context, hub *Hub) context.Context {
|
||||
return context.WithValue(ctx, HubContextKey, hub)
|
||||
|
||||
196
vendor/github.com/getsentry/sentry-go/interfaces.go
сгенерированный
поставляемый
196
vendor/github.com/getsentry/sentry-go/interfaces.go
сгенерированный
поставляемый
@@ -52,31 +52,42 @@ type BreadcrumbHint map[string]interface{}
|
||||
// Breadcrumb specifies an application event that occurred before a Sentry event.
|
||||
// An event may contain one or more breadcrumbs.
|
||||
type Breadcrumb struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Category string `json:"category,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
Level Level `json:"level,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
Timestamp time.Time `json:"timestamp"`
|
||||
Type string `json:"type,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: provide constants for known breadcrumb types.
|
||||
// See https://develop.sentry.dev/sdk/event-payloads/breadcrumbs/#breadcrumb-types.
|
||||
|
||||
// MarshalJSON converts the Breadcrumb struct to JSON.
|
||||
func (b *Breadcrumb) MarshalJSON() ([]byte, error) {
|
||||
type alias Breadcrumb
|
||||
// encoding/json doesn't support the "omitempty" option for struct types.
|
||||
// See https://golang.org/issues/11939.
|
||||
// This implementation of MarshalJSON shadows the original Timestamp field
|
||||
// forcing it to be omitted when the Timestamp is the zero value of
|
||||
// time.Time.
|
||||
// We want to omit time.Time zero values, otherwise the server will try to
|
||||
// interpret dates too far in the past. However, encoding/json doesn't
|
||||
// support the "omitempty" option for struct types. See
|
||||
// https://golang.org/issues/11939.
|
||||
//
|
||||
// We overcome the limitation and achieve what we want by shadowing fields
|
||||
// and a few type tricks.
|
||||
|
||||
// breadcrumb aliases Breadcrumb to allow calling json.Marshal without an
|
||||
// infinite loop. It preserves all fields while none of the attached
|
||||
// methods.
|
||||
type breadcrumb Breadcrumb
|
||||
|
||||
if b.Timestamp.IsZero() {
|
||||
return json.Marshal(&struct {
|
||||
*alias
|
||||
return json.Marshal(struct {
|
||||
// Embed all of the fields of Breadcrumb.
|
||||
*breadcrumb
|
||||
// Timestamp shadows the original Timestamp field and is meant to
|
||||
// remain nil, triggering the omitempty behavior.
|
||||
Timestamp json.RawMessage `json:"timestamp,omitempty"`
|
||||
}{
|
||||
alias: (*alias)(b),
|
||||
})
|
||||
}{breadcrumb: (*breadcrumb)(b)})
|
||||
}
|
||||
return json.Marshal((*alias)(b))
|
||||
return json.Marshal((*breadcrumb)(b))
|
||||
}
|
||||
|
||||
// User describes the user associated with an Event. If this is used, at least
|
||||
@@ -139,12 +150,11 @@ func NewRequest(r *http.Request) *Request {
|
||||
|
||||
// Exception specifies an error that occurred.
|
||||
type Exception struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Module string `json:"module,omitempty"`
|
||||
ThreadID string `json:"thread_id,omitempty"`
|
||||
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
|
||||
RawStacktrace *Stacktrace `json:"raw_stacktrace,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
Value string `json:"value,omitempty"`
|
||||
Module string `json:"module,omitempty"`
|
||||
ThreadID string `json:"thread_id,omitempty"`
|
||||
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
|
||||
}
|
||||
|
||||
// EventID is a hexadecimal string representing a unique uuid4 for an Event.
|
||||
@@ -176,51 +186,99 @@ type Event struct {
|
||||
Request *Request `json:"request,omitempty"`
|
||||
Exception []Exception `json:"exception,omitempty"`
|
||||
|
||||
// Experimental: This is part of a beta feature of the SDK. The fields below
|
||||
// are only relevant for transactions.
|
||||
Type string `json:"type,omitempty"`
|
||||
StartTimestamp time.Time `json:"start_timestamp"`
|
||||
Spans []*Span `json:"spans,omitempty"`
|
||||
// The fields below are only relevant for transactions.
|
||||
|
||||
Type string `json:"type,omitempty"`
|
||||
StartTime time.Time `json:"start_timestamp"`
|
||||
Spans []*Span `json:"spans,omitempty"`
|
||||
}
|
||||
|
||||
// TODO: Event.Contexts map[string]interface{} => map[string]EventContext,
|
||||
// to prevent accidentally storing T when we mean *T.
|
||||
// For example, the TraceContext must be stored as *TraceContext to pick up the
|
||||
// MarshalJSON method (and avoid copying).
|
||||
// type EventContext interface{ EventContext() }
|
||||
|
||||
// MarshalJSON converts the Event struct to JSON.
|
||||
func (e *Event) MarshalJSON() ([]byte, error) {
|
||||
// We want to omit time.Time zero values, otherwise the server will try to
|
||||
// interpret dates too far in the past. However, encoding/json doesn't
|
||||
// support the "omitempty" option for struct types. See
|
||||
// https://golang.org/issues/11939.
|
||||
//
|
||||
// We overcome the limitation and achieve what we want by shadowing fields
|
||||
// and a few type tricks.
|
||||
if e.Type == transactionType {
|
||||
return e.transactionMarshalJSON()
|
||||
}
|
||||
return e.defaultMarshalJSON()
|
||||
}
|
||||
|
||||
func (e *Event) defaultMarshalJSON() ([]byte, error) {
|
||||
// event aliases Event to allow calling json.Marshal without an infinite
|
||||
// loop. It preserves all fields of Event while none of the attached
|
||||
// methods.
|
||||
// loop. It preserves all fields while none of the attached methods.
|
||||
type event Event
|
||||
|
||||
// Transactions are marshaled in the standard way how json.Marshal works.
|
||||
if e.Type == transactionType {
|
||||
return json.Marshal((*event)(e))
|
||||
}
|
||||
|
||||
// errorEvent is like Event with some shadowed fields for customizing the
|
||||
// JSON serialization of regular "error events".
|
||||
// errorEvent is like Event with shadowed fields for customizing JSON
|
||||
// marshaling.
|
||||
type errorEvent struct {
|
||||
*event
|
||||
|
||||
// encoding/json doesn't support the omitempty option for struct types.
|
||||
// See https://golang.org/issues/11939.
|
||||
// We shadow the original Event.Timestamp field with a json.RawMessage.
|
||||
// This allows us to include the timestamp when non-zero and omit it
|
||||
// otherwise.
|
||||
// Timestamp shadows the original Timestamp field. It allows us to
|
||||
// include the timestamp when non-zero and omit it otherwise.
|
||||
Timestamp json.RawMessage `json:"timestamp,omitempty"`
|
||||
|
||||
// The fields below are not part of the regular "error events" and only
|
||||
// make sense to be sent for transactions. They shadow the respective
|
||||
// fields in Event and are meant to remain nil, triggering the omitempty
|
||||
// behavior.
|
||||
Type json.RawMessage `json:"type,omitempty"`
|
||||
StartTimestamp json.RawMessage `json:"start_timestamp,omitempty"`
|
||||
Spans json.RawMessage `json:"spans,omitempty"`
|
||||
// The fields below are not part of error events and only make sense to
|
||||
// be sent for transactions. They shadow the respective fields in Event
|
||||
// and are meant to remain nil, triggering the omitempty behavior.
|
||||
|
||||
Type json.RawMessage `json:"type,omitempty"`
|
||||
StartTime json.RawMessage `json:"start_timestamp,omitempty"`
|
||||
Spans json.RawMessage `json:"spans,omitempty"`
|
||||
}
|
||||
|
||||
x := &errorEvent{event: (*event)(e)}
|
||||
x := errorEvent{event: (*event)(e)}
|
||||
if !e.Timestamp.IsZero() {
|
||||
x.Timestamp = append(x.Timestamp, '"')
|
||||
x.Timestamp = e.Timestamp.UTC().AppendFormat(x.Timestamp, time.RFC3339Nano)
|
||||
x.Timestamp = append(x.Timestamp, '"')
|
||||
b, err := e.Timestamp.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x.Timestamp = b
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (e *Event) transactionMarshalJSON() ([]byte, error) {
|
||||
// event aliases Event to allow calling json.Marshal without an infinite
|
||||
// loop. It preserves all fields while none of the attached methods.
|
||||
type event Event
|
||||
|
||||
// transactionEvent is like Event with shadowed fields for customizing JSON
|
||||
// marshaling.
|
||||
type transactionEvent struct {
|
||||
*event
|
||||
|
||||
// The fields below shadow the respective fields in Event. They allow us
|
||||
// to include timestamps when non-zero and omit them otherwise.
|
||||
|
||||
StartTime json.RawMessage `json:"start_timestamp,omitempty"`
|
||||
Timestamp json.RawMessage `json:"timestamp,omitempty"`
|
||||
}
|
||||
|
||||
x := transactionEvent{event: (*event)(e)}
|
||||
if !e.Timestamp.IsZero() {
|
||||
b, err := e.Timestamp.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x.Timestamp = b
|
||||
}
|
||||
if !e.StartTime.IsZero() {
|
||||
b, err := e.StartTime.MarshalJSON()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x.StartTime = b
|
||||
}
|
||||
return json.Marshal(x)
|
||||
}
|
||||
@@ -238,12 +296,11 @@ func NewEvent() *Event {
|
||||
|
||||
// Thread specifies threads that were running at the time of an event.
|
||||
type Thread struct {
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
|
||||
RawStacktrace *Stacktrace `json:"raw_stacktrace,omitempty"`
|
||||
Crashed bool `json:"crashed,omitempty"`
|
||||
Current bool `json:"current,omitempty"`
|
||||
ID string `json:"id,omitempty"`
|
||||
Name string `json:"name,omitempty"`
|
||||
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
|
||||
Crashed bool `json:"crashed,omitempty"`
|
||||
Current bool `json:"current,omitempty"`
|
||||
}
|
||||
|
||||
// EventHint contains information that can be associated with an Event.
|
||||
@@ -256,30 +313,3 @@ type EventHint struct {
|
||||
Request *http.Request
|
||||
Response *http.Response
|
||||
}
|
||||
|
||||
// TraceContext describes the context of the trace.
|
||||
//
|
||||
// Experimental: This is part of a beta feature of the SDK.
|
||||
type TraceContext struct {
|
||||
TraceID string `json:"trace_id"`
|
||||
SpanID string `json:"span_id"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
// Span describes a timed unit of work in a trace.
|
||||
//
|
||||
// Experimental: This is part of a beta feature of the SDK.
|
||||
type Span struct {
|
||||
TraceID string `json:"trace_id"`
|
||||
SpanID string `json:"span_id"`
|
||||
ParentSpanID string `json:"parent_span_id,omitempty"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Status string `json:"status,omitempty"`
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
StartTimestamp time.Time `json:"start_timestamp"`
|
||||
EndTimestamp time.Time `json:"timestamp"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
23
vendor/github.com/getsentry/sentry-go/internal/crypto/randutil/randutil.go
сгенерированный
поставляемый
Обычный файл
23
vendor/github.com/getsentry/sentry-go/internal/crypto/randutil/randutil.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,23 @@
|
||||
package randutil
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/binary"
|
||||
)
|
||||
|
||||
const (
|
||||
floatMax = 1 << 53
|
||||
floatMask = floatMax - 1
|
||||
)
|
||||
|
||||
// Float64 returns a cryptographically secure random number in [0.0, 1.0).
|
||||
func Float64() float64 {
|
||||
// The implementation is, in essence:
|
||||
// return float64(rand.Int63n(1<<53)) / (1<<53)
|
||||
b := make([]byte, 8)
|
||||
_, err := rand.Read(b)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return float64(binary.LittleEndian.Uint64(b)&floatMask) / floatMax
|
||||
}
|
||||
45
vendor/github.com/getsentry/sentry-go/internal/debug/transport.go
сгенерированный
поставляемый
Обычный файл
45
vendor/github.com/getsentry/sentry-go/internal/debug/transport.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,45 @@
|
||||
package debug
|
||||
|
||||
import (
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/httputil"
|
||||
)
|
||||
|
||||
// Transport implements http.RoundTripper and can be used to wrap other HTTP
|
||||
// transports to dump request and responses for debugging.
|
||||
type Transport struct {
|
||||
http.RoundTripper
|
||||
Output io.Writer
|
||||
}
|
||||
|
||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
b, err := httputil.DumpRequestOut(req, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = t.Output.Write(ensureTrailingNewline(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := t.RoundTripper.RoundTrip(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
b, err = httputil.DumpResponse(resp, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = t.Output.Write(ensureTrailingNewline(b))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func ensureTrailingNewline(b []byte) []byte {
|
||||
if len(b) > 0 && b[len(b)-1] != '\n' {
|
||||
b = append(b, '\n')
|
||||
}
|
||||
return b
|
||||
}
|
||||
16
vendor/github.com/getsentry/sentry-go/scope.go
сгенерированный
поставляемый
16
vendor/github.com/getsentry/sentry-go/scope.go
сгенерированный
поставляемый
@@ -63,7 +63,7 @@ func NewScope() *Scope {
|
||||
// and optionally throws the old one if limit is reached.
|
||||
func (scope *Scope) AddBreadcrumb(breadcrumb *Breadcrumb, limit int) {
|
||||
if breadcrumb.Timestamp.IsZero() {
|
||||
breadcrumb.Timestamp = time.Now().UTC()
|
||||
breadcrumb.Timestamp = time.Now()
|
||||
}
|
||||
|
||||
scope.mu.Lock()
|
||||
@@ -278,12 +278,20 @@ func (scope *Scope) SetLevel(level Level) {
|
||||
scope.level = level
|
||||
}
|
||||
|
||||
// SetTransaction sets new transaction name for the current transaction.
|
||||
func (scope *Scope) SetTransaction(transactionName string) {
|
||||
// SetTransaction sets the transaction name for the current transaction.
|
||||
func (scope *Scope) SetTransaction(name string) {
|
||||
scope.mu.Lock()
|
||||
defer scope.mu.Unlock()
|
||||
|
||||
scope.transaction = transactionName
|
||||
scope.transaction = name
|
||||
}
|
||||
|
||||
// Transaction returns the transaction name for the current transaction.
|
||||
func (scope *Scope) Transaction() (name string) {
|
||||
scope.mu.RLock()
|
||||
defer scope.mu.RUnlock()
|
||||
|
||||
return scope.transaction
|
||||
}
|
||||
|
||||
// Clone returns a copy of the current scope with all data copied over.
|
||||
|
||||
4
vendor/github.com/getsentry/sentry-go/sentry.go
сгенерированный
поставляемый
4
vendor/github.com/getsentry/sentry-go/sentry.go
сгенерированный
поставляемый
@@ -6,7 +6,7 @@ import (
|
||||
)
|
||||
|
||||
// Version is the version of the SDK.
|
||||
const Version = "0.7.0"
|
||||
const Version = "0.9.0"
|
||||
|
||||
// apiVersion is the minimum version of the Sentry API compatible with the
|
||||
// sentry-go SDK.
|
||||
@@ -92,7 +92,7 @@ func ConfigureScope(f func(scope *Scope)) {
|
||||
hub.ConfigureScope(f)
|
||||
}
|
||||
|
||||
// PushScope is a shorthand for CurrentHub().PushPushScope.
|
||||
// PushScope is a shorthand for CurrentHub().PushScope.
|
||||
func PushScope() {
|
||||
hub := CurrentHub()
|
||||
hub.PushScope()
|
||||
|
||||
57
vendor/github.com/getsentry/sentry-go/span_recorder.go
сгенерированный
поставляемый
Обычный файл
57
vendor/github.com/getsentry/sentry-go/span_recorder.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,57 @@
|
||||
package sentry
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
|
||||
// maxSpans limits the number of recorded spans per transaction. The limit is
|
||||
// meant to bound memory usage and prevent too large transaction events that
|
||||
// would be rejected by Sentry.
|
||||
const maxSpans = 1000
|
||||
|
||||
// A spanRecorder stores a span tree that makes up a transaction. Safe for
|
||||
// concurrent use. It is okay to add child spans from multiple goroutines.
|
||||
type spanRecorder struct {
|
||||
mu sync.Mutex
|
||||
spans []*Span
|
||||
overflowOnce sync.Once
|
||||
}
|
||||
|
||||
// record stores a span. The first stored span is assumed to be the root of a
|
||||
// span tree.
|
||||
func (r *spanRecorder) record(s *Span) {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if len(r.spans) >= maxSpans {
|
||||
r.overflowOnce.Do(func() {
|
||||
root := r.spans[0]
|
||||
Logger.Printf("Too many spans: dropping spans from transaction with TraceID=%s SpanID=%s limit=%d",
|
||||
root.TraceID, root.SpanID, maxSpans)
|
||||
})
|
||||
// TODO(tracing): mark the transaction event in some way to
|
||||
// communicate that spans were dropped.
|
||||
return
|
||||
}
|
||||
r.spans = append(r.spans, s)
|
||||
}
|
||||
|
||||
// root returns the first recorded span. Returns nil if none have been recorded.
|
||||
func (r *spanRecorder) root() *Span {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if len(r.spans) == 0 {
|
||||
return nil
|
||||
}
|
||||
return r.spans[0]
|
||||
}
|
||||
|
||||
// children returns a list of all recorded spans, except the root. Returns nil
|
||||
// if there are no children.
|
||||
func (r *spanRecorder) children() []*Span {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
if len(r.spans) < 2 {
|
||||
return nil
|
||||
}
|
||||
return r.spans[1:]
|
||||
}
|
||||
171
vendor/github.com/getsentry/sentry-go/traces_sampler.go
сгенерированный
поставляемый
Обычный файл
171
vendor/github.com/getsentry/sentry-go/traces_sampler.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,171 @@
|
||||
package sentry
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/getsentry/sentry-go/internal/crypto/randutil"
|
||||
)
|
||||
|
||||
// A TracesSampler makes sampling decisions for spans.
|
||||
//
|
||||
// In addition to the sampling context passed to the Sample method,
|
||||
// implementations may keep and use internal state to make decisions.
|
||||
//
|
||||
// Sampling is one of the last steps when starting a new span, such that the
|
||||
// sampler can inspect most of the state of the span to make a decision.
|
||||
//
|
||||
// Implementations must be safe for concurrent use by multiple goroutines.
|
||||
type TracesSampler interface {
|
||||
Sample(ctx SamplingContext) Sampled
|
||||
}
|
||||
|
||||
// Implementation note:
|
||||
//
|
||||
// TracesSampler.Sample return type is Sampled (instead of bool or float64), so
|
||||
// that we can compose samplers by letting a sampler return SampledUndefined to
|
||||
// defer the decision to the next sampler.
|
||||
//
|
||||
// For example, a hypothetical InheritFromParentSampler would return
|
||||
// SampledUndefined if there is no parent span in the SamplingContext, deferring
|
||||
// the sampling decision to another sampler, like a UniformSampler.
|
||||
//
|
||||
// var _ TracesSampler = sentry.TracesSamplers{
|
||||
// sentry.InheritFromParentSampler,
|
||||
// sentry.UniformTracesSampler(0.1),
|
||||
// }
|
||||
//
|
||||
// Another example, we can provide a sampler that returns SampledFalse if the
|
||||
// SamplingContext matches some condition, and SampledUndefined otherwise:
|
||||
//
|
||||
// var _ TracesSampler = sentry.TracesSamplers{
|
||||
// sentry.IgnoreTransaction(regexp.MustCompile(`^\w+ /(favicon.ico|healthz)`),
|
||||
// sentry.InheritFromParentSampler,
|
||||
// sentry.UniformTracesSampler(0.1),
|
||||
// }
|
||||
//
|
||||
// If after running all samplers the decision is still undefined, the
|
||||
// span/transaction is not sampled.
|
||||
|
||||
// A SamplingContext is passed to a TracesSampler to determine a sampling
|
||||
// decision.
|
||||
type SamplingContext struct {
|
||||
Span *Span // The current span, always non-nil.
|
||||
Parent *Span // The parent span, may be nil.
|
||||
}
|
||||
|
||||
// TODO(tracing): possibly expand SamplingContext to include custom /
|
||||
// user-provided data.
|
||||
//
|
||||
// Unlike in other SDKs, the current http.Request is not part of the
|
||||
// SamplingContext to avoid bloating it with possibly unnecessary values that
|
||||
// could confuse people or have negative performance consequences.
|
||||
//
|
||||
// For the request to be provided in a SamplingContext, a request pointer would
|
||||
// most likely need to be stored in the span context and it would open precedent
|
||||
// for more arbitrary data like fasthttp.Request.
|
||||
//
|
||||
// Users wanting to influence the sampling decision based on the request can
|
||||
// still do so, either by updating the transaction directly on their HTTP
|
||||
// handler:
|
||||
//
|
||||
// func(w http.ResponseWriter, r *http.Request) {
|
||||
// transaction := sentry.TransactionFromContext(r.Context())
|
||||
// if r.Header.Get("X-Custom-Sampling") == "yes" {
|
||||
// transaction.Sampled = sentry.SampledTrue
|
||||
// } else {
|
||||
// transaction.Sampled = sentry.SampledFalse
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Or by having their own middleware that stores arbitrary data in the request
|
||||
// context (a pointer to the request itself included):
|
||||
//
|
||||
// type myContextKey struct{}
|
||||
// type myContextData struct {
|
||||
// request *http.Request
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// func middleware(h http.Handler) http.Handler {
|
||||
// return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// data := &myContextData{
|
||||
// request: r,
|
||||
// }
|
||||
// ctx := context.WithValue(r.Context(), myContextKey{}, data)
|
||||
// h.ServeHTTP(w, r.WithContext(ctx))
|
||||
// })
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// err := sentry.Init(sentry.ClientOptions{
|
||||
// // A custom TracesSampler can access data from the span's context:
|
||||
// TracesSampler: sentry.TracesSamplerFunc(func(ctx sentry.SamplingContext) bool {
|
||||
// data, ok := ctx.Span.Context().Value(myContextKey{}).(*myContextData)
|
||||
// if !ok {
|
||||
// return false
|
||||
// }
|
||||
// return data.request.URL.Hostname() == "example.com"
|
||||
// }),
|
||||
// })
|
||||
// // ...
|
||||
// }
|
||||
//
|
||||
// Note, however, that for the middleware to be effective, it would have to run
|
||||
// before sentryhttp's own middleware, meaning the middleware itself is not
|
||||
// instrumented to send panics to Sentry and it is not part of the timed
|
||||
// transaction.
|
||||
//
|
||||
// If neither of those prove to be sufficient, we can consider including a
|
||||
// (possibly nil) *http.Request field to SamplingContext. In that case, the SDK
|
||||
// would need to track the request either in the Scope or the Span.Context.
|
||||
//
|
||||
// Alternatively, add a map-like type or simply a generic interface{} similar to
|
||||
// the CustomSamplingContext type in the Java SDK:
|
||||
//
|
||||
// type SamplingContext struct {
|
||||
// Span *Span // The current span, always non-nil.
|
||||
// Parent *Span // The parent span, may be nil.
|
||||
// CustomData interface{}
|
||||
// }
|
||||
//
|
||||
// func CustomSamplingContext(data interface{}) SpanOption {
|
||||
// return func(s *Span) {
|
||||
// s.customSamplingContext = data
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// func main() {
|
||||
// // ...
|
||||
// span := sentry.StartSpan(ctx, "op", CustomSamplingContext(data))
|
||||
// // ...
|
||||
// }
|
||||
|
||||
// The TracesSamplerFunc type is an adapter to allow the use of ordinary
|
||||
// functions as a TracesSampler.
|
||||
type TracesSamplerFunc func(ctx SamplingContext) Sampled
|
||||
|
||||
var _ TracesSampler = TracesSamplerFunc(nil)
|
||||
|
||||
func (f TracesSamplerFunc) Sample(ctx SamplingContext) Sampled {
|
||||
return f(ctx)
|
||||
}
|
||||
|
||||
// UniformTracesSampler is a TracesSampler that samples root spans randomly at a
|
||||
// uniform rate.
|
||||
type UniformTracesSampler float64
|
||||
|
||||
var _ TracesSampler = UniformTracesSampler(0)
|
||||
|
||||
func (s UniformTracesSampler) Sample(ctx SamplingContext) Sampled {
|
||||
if s < 0.0 || s > 1.0 {
|
||||
panic(fmt.Errorf("sampling rate out of range [0.0, 1.0]: %f", s))
|
||||
}
|
||||
if randutil.Float64() < float64(s) {
|
||||
return SampledTrue
|
||||
}
|
||||
return SampledFalse
|
||||
}
|
||||
|
||||
// TODO(tracing): implement and export basic TracesSampler implementations:
|
||||
// parent-based, span ID / trace ID based, etc. It should be possible to compose
|
||||
// parent-based with other samplers.
|
||||
594
vendor/github.com/getsentry/sentry-go/tracing.go
сгенерированный
поставляемый
Обычный файл
594
vendor/github.com/getsentry/sentry-go/tracing.go
сгенерированный
поставляемый
Обычный файл
@@ -0,0 +1,594 @@
|
||||
package sentry
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// A Span is the building block of a Sentry transaction. Spans build up a tree
|
||||
// structure of timed operations. The span tree makes up a transaction event
|
||||
// that is sent to Sentry when the root span is finished.
|
||||
//
|
||||
// Spans must be started with either StartSpan or Span.StartChild.
|
||||
type Span struct { //nolint: maligned // prefer readability over optimal memory layout (see note below *)
|
||||
TraceID TraceID `json:"trace_id"`
|
||||
SpanID SpanID `json:"span_id"`
|
||||
ParentSpanID SpanID `json:"parent_span_id"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Status SpanStatus `json:"status,omitempty"`
|
||||
Tags map[string]string `json:"tags,omitempty"`
|
||||
StartTime time.Time `json:"start_timestamp"`
|
||||
EndTime time.Time `json:"timestamp"`
|
||||
Data map[string]interface{} `json:"data,omitempty"`
|
||||
|
||||
Sampled Sampled `json:"-"`
|
||||
|
||||
// ctx is the context where the span was started. Always non-nil.
|
||||
ctx context.Context
|
||||
|
||||
// parent refers to the immediate local parent span. A remote parent span is
|
||||
// only referenced by setting ParentSpanID.
|
||||
parent *Span
|
||||
|
||||
// isTransaction is true only for the root span of a local span tree. The
|
||||
// root span is the first span started in a context. Note that a local root
|
||||
// span may have a remote parent belonging to the same trace, therefore
|
||||
// isTransaction depends on ctx and not on parent.
|
||||
isTransaction bool
|
||||
|
||||
// recorder stores all spans in a transaction. Guaranteed to be non-nil.
|
||||
recorder *spanRecorder
|
||||
}
|
||||
|
||||
// (*) Note on maligned:
|
||||
//
|
||||
// We prefer readability over optimal memory layout. If we ever decide to
|
||||
// reorder fields, we can use a tool:
|
||||
//
|
||||
// go run honnef.co/go/tools/cmd/structlayout -json . Span | go run honnef.co/go/tools/cmd/structlayout-optimize
|
||||
//
|
||||
// Other structs would deserve reordering as well, for example Event.
|
||||
|
||||
// TODO: make Span.Tags and Span.Data opaque types (struct{unexported []slice}).
|
||||
// An opaque type allows us to add methods and make it more convenient to use
|
||||
// than maps, because maps require careful nil checks to use properly or rely on
|
||||
// explicit initialization for every span, even when there might be no
|
||||
// tags/data. For Span.Data, must gracefully handle values that cannot be
|
||||
// marshaled into JSON (see transport.go:getRequestBodyFromEvent).
|
||||
|
||||
// StartSpan starts a new span to describe an operation. The new span will be a
|
||||
// child of the last span stored in ctx, if any.
|
||||
//
|
||||
// One or more options can be used to modify the span properties. Typically one
|
||||
// option as a function literal is enough. Combining multiple options can be
|
||||
// useful to define and reuse specific properties with named functions.
|
||||
//
|
||||
// Caller should call the Finish method on the span to mark its end. Finishing a
|
||||
// root span sends the span and all of its children, recursively, as a
|
||||
// transaction to Sentry.
|
||||
func StartSpan(ctx context.Context, operation string, options ...SpanOption) *Span {
|
||||
parent, hasParent := ctx.Value(spanContextKey{}).(*Span)
|
||||
var span Span
|
||||
span = Span{
|
||||
// defaults
|
||||
Op: operation,
|
||||
StartTime: time.Now(),
|
||||
|
||||
ctx: context.WithValue(ctx, spanContextKey{}, &span),
|
||||
parent: parent,
|
||||
isTransaction: !hasParent,
|
||||
}
|
||||
if hasParent {
|
||||
span.TraceID = parent.TraceID
|
||||
} else {
|
||||
// Implementation note:
|
||||
//
|
||||
// While math/rand is ~2x faster than crypto/rand (exact
|
||||
// difference depends on hardware / OS), crypto/rand is probably
|
||||
// fast enough and a safer choice.
|
||||
//
|
||||
// For reference, OpenTelemetry [1] uses crypto/rand to seed
|
||||
// math/rand. AFAICT this approach does not preserve the
|
||||
// properties from crypto/rand that make it suitable for
|
||||
// cryptography. While it might be debatable whether those
|
||||
// properties are important for us here, again, we're taking the
|
||||
// safer path.
|
||||
//
|
||||
// See [2a] & [2b] for a discussion of some of the properties we
|
||||
// obtain by using crypto/rand and [3a] & [3b] for why we avoid
|
||||
// math/rand.
|
||||
//
|
||||
// Because the math/rand seed has only 64 bits (int64), if the
|
||||
// first thing we do after seeding an RNG is to read in a random
|
||||
// TraceID, there are only 2^64 possible values. Compared to
|
||||
// UUID v4 that have 122 random bits, there is a much greater
|
||||
// chance of collision [4a] & [4b].
|
||||
//
|
||||
// [1]: https://github.com/open-telemetry/opentelemetry-go/blob/958041ddf619a128/sdk/trace/trace.go#L25-L31
|
||||
// [2a]: https://security.stackexchange.com/q/120352/246345
|
||||
// [2b]: https://security.stackexchange.com/a/120365/246345
|
||||
// [3a]: https://github.com/golang/go/issues/11871#issuecomment-126333686
|
||||
// [3b]: https://github.com/golang/go/issues/11871#issuecomment-126357889
|
||||
// [4a]: https://en.wikipedia.org/wiki/Universally_unique_identifier#Collisions
|
||||
// [4b]: https://www.wolframalpha.com/input/?i=sqrt%282*2%5E64*ln%281%2F%281-0.5%29%29%29
|
||||
_, err := rand.Read(span.TraceID[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
_, err := rand.Read(span.SpanID[:])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if hasParent {
|
||||
span.ParentSpanID = parent.SpanID
|
||||
}
|
||||
|
||||
// Apply options to override defaults.
|
||||
for _, option := range options {
|
||||
option(&span)
|
||||
}
|
||||
|
||||
span.Sampled = span.sample()
|
||||
|
||||
if hasParent {
|
||||
span.recorder = parent.spanRecorder()
|
||||
} else {
|
||||
span.recorder = &spanRecorder{}
|
||||
}
|
||||
span.recorder.record(&span)
|
||||
|
||||
// Update scope so that all events include a trace context, allowing
|
||||
// Sentry to correlate errors to transactions/spans.
|
||||
hubFromContext(ctx).Scope().SetContext("trace", span.traceContext())
|
||||
|
||||
return &span
|
||||
}
|
||||
|
||||
// Finish sets the span's end time, unless already set. If the span is the root
|
||||
// of a span tree, Finish sends the span tree to Sentry as a transaction.
|
||||
func (s *Span) Finish() {
|
||||
// TODO(tracing): maybe make Finish run at most once, such that
|
||||
// (incorrectly) calling it twice never double sends to Sentry.
|
||||
|
||||
if s.EndTime.IsZero() {
|
||||
s.EndTime = monotonicTimeSince(s.StartTime)
|
||||
}
|
||||
if !s.Sampled.Bool() {
|
||||
return
|
||||
}
|
||||
event := s.toEvent()
|
||||
if event == nil {
|
||||
return
|
||||
}
|
||||
|
||||
// TODO(tracing): add breadcrumbs
|
||||
// (see https://github.com/getsentry/sentry-python/blob/f6f3525f8812f609/sentry_sdk/tracing.py#L372)
|
||||
|
||||
hub := hubFromContext(s.ctx)
|
||||
if hub.Scope().Transaction() == "" {
|
||||
Logger.Printf("Missing transaction name for span with op = %q", s.Op)
|
||||
}
|
||||
hub.CaptureEvent(event)
|
||||
}
|
||||
|
||||
// Context returns the context containing the span.
|
||||
func (s *Span) Context() context.Context { return s.ctx }
|
||||
|
||||
// StartChild starts a new child span.
|
||||
//
|
||||
// The call span.StartChild(operation, options...) is a shortcut for
|
||||
// StartSpan(span.Context(), operation, options...).
|
||||
func (s *Span) StartChild(operation string, options ...SpanOption) *Span {
|
||||
return StartSpan(s.Context(), operation, options...)
|
||||
}
|
||||
|
||||
// SetTag sets a tag on the span. It is recommended to use SetTag instead of
|
||||
// accessing the tags map directly as SetTag takes care of initializing the map
|
||||
// when necessary.
|
||||
func (s *Span) SetTag(name, value string) {
|
||||
if s.Tags == nil {
|
||||
s.Tags = make(map[string]string)
|
||||
}
|
||||
s.Tags[name] = value
|
||||
}
|
||||
|
||||
// TODO(tracing): maybe add shortcuts to get/set transaction name. Right now the
|
||||
// transaction name is in the Scope, as it has existed there historically, prior
|
||||
// to tracing.
|
||||
//
|
||||
// See Scope.Transaction() and Scope.SetTransaction().
|
||||
//
|
||||
// func (s *Span) TransactionName() string
|
||||
// func (s *Span) SetTransactionName(name string)
|
||||
|
||||
// ToSentryTrace returns the trace propagation value used with the sentry-trace
|
||||
// HTTP header.
|
||||
func (s *Span) ToSentryTrace() string {
|
||||
// TODO(tracing): add instrumentation for outgoing HTTP requests using
|
||||
// ToSentryTrace.
|
||||
var b strings.Builder
|
||||
fmt.Fprintf(&b, "%s-%s", s.TraceID.Hex(), s.SpanID.Hex())
|
||||
switch s.Sampled {
|
||||
case SampledTrue:
|
||||
b.WriteString("-1")
|
||||
case SampledFalse:
|
||||
b.WriteString("-0")
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// sentryTracePattern matches either
|
||||
//
|
||||
// TRACE_ID - SPAN_ID
|
||||
// [[:xdigit:]]{32}-[[:xdigit:]]{16}
|
||||
//
|
||||
// or
|
||||
//
|
||||
// TRACE_ID - SPAN_ID - SAMPLED
|
||||
// [[:xdigit:]]{32}-[[:xdigit:]]{16}-[01]
|
||||
var sentryTracePattern = regexp.MustCompile(`^([[:xdigit:]]{32})-([[:xdigit:]]{16})(?:-([01]))?$`)
|
||||
|
||||
// updateFromSentryTrace parses a sentry-trace HTTP header (as returned by
|
||||
// ToSentryTrace) and updates fields of the span. If the header cannot be
|
||||
// recognized as valid, the span is left unchanged.
|
||||
func (s *Span) updateFromSentryTrace(header []byte) {
|
||||
m := sentryTracePattern.FindSubmatch(header)
|
||||
if m == nil {
|
||||
// no match
|
||||
return
|
||||
}
|
||||
_, _ = hex.Decode(s.TraceID[:], m[1])
|
||||
_, _ = hex.Decode(s.ParentSpanID[:], m[2])
|
||||
if len(m[3]) != 0 {
|
||||
switch m[3][0] {
|
||||
case '0':
|
||||
s.Sampled = SampledFalse
|
||||
case '1':
|
||||
s.Sampled = SampledTrue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Span) MarshalJSON() ([]byte, error) {
|
||||
// span aliases Span to allow calling json.Marshal without an infinite loop.
|
||||
// It preserves all fields while none of the attached methods.
|
||||
type span Span
|
||||
var parentSpanID string
|
||||
if s.ParentSpanID != zeroSpanID {
|
||||
parentSpanID = s.ParentSpanID.String()
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
*span
|
||||
ParentSpanID string `json:"parent_span_id,omitempty"`
|
||||
}{
|
||||
span: (*span)(s),
|
||||
ParentSpanID: parentSpanID,
|
||||
})
|
||||
}
|
||||
|
||||
func (s *Span) sample() Sampled {
|
||||
// https://develop.sentry.dev/sdk/unified-api/tracing/#sampling
|
||||
// #1 explicit sampling decision via StartSpan options.
|
||||
if s.Sampled != SampledUndefined {
|
||||
return s.Sampled
|
||||
}
|
||||
hub := hubFromContext(s.ctx)
|
||||
var clientOptions ClientOptions
|
||||
client := hub.Client()
|
||||
if client != nil {
|
||||
clientOptions = hub.Client().Options()
|
||||
}
|
||||
samplingContext := SamplingContext{Span: s, Parent: s.parent}
|
||||
// Variant for non-transaction spans: they inherit the parent decision.
|
||||
// TracesSampler only runs for the root span.
|
||||
// Note: non-transaction should always have a parent, but we check both
|
||||
// conditions anyway -- the first for semantic meaning, the second to
|
||||
// avoid a nil pointer dereference.
|
||||
if !s.isTransaction && s.parent != nil {
|
||||
return s.parent.Sampled
|
||||
}
|
||||
// #2 use TracesSampler from ClientOptions.
|
||||
sampler := clientOptions.TracesSampler
|
||||
if sampler != nil {
|
||||
return sampler.Sample(samplingContext)
|
||||
}
|
||||
// #3 inherit parent decision.
|
||||
if s.parent != nil {
|
||||
return s.parent.Sampled
|
||||
}
|
||||
// #4 uniform sampling using TracesSampleRate.
|
||||
sampler = UniformTracesSampler(clientOptions.TracesSampleRate)
|
||||
return sampler.Sample(samplingContext)
|
||||
}
|
||||
|
||||
func (s *Span) toEvent() *Event {
|
||||
if !s.isTransaction {
|
||||
return nil // only transactions can be transformed into events
|
||||
}
|
||||
hub := hubFromContext(s.ctx)
|
||||
|
||||
children := s.recorder.children()
|
||||
finished := make([]*Span, 0, len(children))
|
||||
for _, child := range children {
|
||||
if child.EndTime.IsZero() {
|
||||
Logger.Printf("Dropped unfinished span: Op=%q TraceID=%s SpanID=%s", child.Op, child.TraceID, child.SpanID)
|
||||
continue
|
||||
}
|
||||
finished = append(finished, child)
|
||||
}
|
||||
|
||||
return &Event{
|
||||
Type: transactionType,
|
||||
Transaction: hub.Scope().Transaction(),
|
||||
Contexts: map[string]interface{}{
|
||||
"trace": s.traceContext(),
|
||||
},
|
||||
Tags: s.Tags,
|
||||
Timestamp: s.EndTime,
|
||||
StartTime: s.StartTime,
|
||||
Spans: finished,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Span) traceContext() *TraceContext {
|
||||
return &TraceContext{
|
||||
TraceID: s.TraceID,
|
||||
SpanID: s.SpanID,
|
||||
ParentSpanID: s.ParentSpanID,
|
||||
Op: s.Op,
|
||||
Description: s.Description,
|
||||
Status: s.Status,
|
||||
}
|
||||
}
|
||||
|
||||
// spanRecorder stores the span tree. Guaranteed to be non-nil.
|
||||
func (s *Span) spanRecorder() *spanRecorder { return s.recorder }
|
||||
|
||||
// TraceID identifies a trace.
|
||||
type TraceID [16]byte
|
||||
|
||||
func (id TraceID) Hex() []byte {
|
||||
b := make([]byte, hex.EncodedLen(len(id)))
|
||||
hex.Encode(b, id[:])
|
||||
return b
|
||||
}
|
||||
|
||||
func (id TraceID) String() string {
|
||||
return string(id.Hex())
|
||||
}
|
||||
|
||||
func (id TraceID) MarshalText() ([]byte, error) {
|
||||
return id.Hex(), nil
|
||||
}
|
||||
|
||||
// SpanID identifies a span.
|
||||
type SpanID [8]byte
|
||||
|
||||
func (id SpanID) Hex() []byte {
|
||||
b := make([]byte, hex.EncodedLen(len(id)))
|
||||
hex.Encode(b, id[:])
|
||||
return b
|
||||
}
|
||||
|
||||
func (id SpanID) String() string {
|
||||
return string(id.Hex())
|
||||
}
|
||||
|
||||
func (id SpanID) MarshalText() ([]byte, error) {
|
||||
return id.Hex(), nil
|
||||
}
|
||||
|
||||
// Zero values of TraceID and SpanID used for comparisons.
|
||||
var (
|
||||
zeroTraceID TraceID
|
||||
zeroSpanID SpanID
|
||||
)
|
||||
|
||||
// SpanStatus is the status of a span.
|
||||
type SpanStatus uint8
|
||||
|
||||
// Implementation note:
|
||||
//
|
||||
// In Relay (ingestion), the SpanStatus type is an enum used as
|
||||
// Annotated<SpanStatus> when embedded in structs, making it effectively
|
||||
// Option<SpanStatus>. It means the status is either null or one of the known
|
||||
// string values.
|
||||
//
|
||||
// In Snuba (search), the SpanStatus is stored as an uint8 and defaulted to 2
|
||||
// ("unknown") when not set. It means that Discover searches for
|
||||
// `transaction.status:unknown` return both transactions/spans with status
|
||||
// `null` or `"unknown"`. Searches for `transaction.status:""` return nothing.
|
||||
//
|
||||
// With that in mind, the Go SDK default is SpanStatusUndefined, which is
|
||||
// null/omitted when serializing to JSON, but integrations may update the status
|
||||
// automatically based on contextual information.
|
||||
|
||||
const (
|
||||
SpanStatusUndefined SpanStatus = iota
|
||||
SpanStatusOK
|
||||
SpanStatusCanceled
|
||||
SpanStatusUnknown
|
||||
SpanStatusInvalidArgument
|
||||
SpanStatusDeadlineExceeded
|
||||
SpanStatusNotFound
|
||||
SpanStatusAlreadyExists
|
||||
SpanStatusPermissionDenied
|
||||
SpanStatusResourceExhausted
|
||||
SpanStatusFailedPrecondition
|
||||
SpanStatusAborted
|
||||
SpanStatusOutOfRange
|
||||
SpanStatusUnimplemented
|
||||
SpanStatusInternalError
|
||||
SpanStatusUnavailable
|
||||
SpanStatusDataLoss
|
||||
SpanStatusUnauthenticated
|
||||
maxSpanStatus
|
||||
)
|
||||
|
||||
func (ss SpanStatus) String() string {
|
||||
if ss >= maxSpanStatus {
|
||||
return ""
|
||||
}
|
||||
m := [maxSpanStatus]string{
|
||||
"",
|
||||
"ok",
|
||||
"cancelled", // [sic]
|
||||
"unknown",
|
||||
"invalid_argument",
|
||||
"deadline_exceeded",
|
||||
"not_found",
|
||||
"already_exists",
|
||||
"permission_denied",
|
||||
"resource_exhausted",
|
||||
"failed_precondition",
|
||||
"aborted",
|
||||
"out_of_range",
|
||||
"unimplemented",
|
||||
"internal_error",
|
||||
"unavailable",
|
||||
"data_loss",
|
||||
"unauthenticated",
|
||||
}
|
||||
return m[ss]
|
||||
}
|
||||
|
||||
func (ss SpanStatus) MarshalJSON() ([]byte, error) {
|
||||
s := ss.String()
|
||||
if s == "" {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return json.Marshal(s)
|
||||
}
|
||||
|
||||
// A TraceContext carries information about an ongoing trace and is meant to be
|
||||
// stored in Event.Contexts (as *TraceContext).
|
||||
type TraceContext struct {
|
||||
TraceID TraceID `json:"trace_id"`
|
||||
SpanID SpanID `json:"span_id"`
|
||||
ParentSpanID SpanID `json:"parent_span_id"`
|
||||
Op string `json:"op,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
Status SpanStatus `json:"status,omitempty"`
|
||||
}
|
||||
|
||||
func (tc *TraceContext) MarshalJSON() ([]byte, error) {
|
||||
// traceContext aliases TraceContext to allow calling json.Marshal without
|
||||
// an infinite loop. It preserves all fields while none of the attached
|
||||
// methods.
|
||||
type traceContext TraceContext
|
||||
var parentSpanID string
|
||||
if tc.ParentSpanID != zeroSpanID {
|
||||
parentSpanID = tc.ParentSpanID.String()
|
||||
}
|
||||
return json.Marshal(struct {
|
||||
*traceContext
|
||||
ParentSpanID string `json:"parent_span_id,omitempty"`
|
||||
}{
|
||||
traceContext: (*traceContext)(tc),
|
||||
ParentSpanID: parentSpanID,
|
||||
})
|
||||
}
|
||||
|
||||
// Sampled signifies a sampling decision.
|
||||
type Sampled int8
|
||||
|
||||
// The possible trace sampling decisions are: SampledFalse, SampledUndefined
|
||||
// (default) and SampledTrue.
|
||||
const (
|
||||
SampledFalse Sampled = -1 + iota
|
||||
SampledUndefined
|
||||
SampledTrue
|
||||
)
|
||||
|
||||
func (s Sampled) String() string {
|
||||
switch s {
|
||||
case SampledFalse:
|
||||
return "SampledFalse"
|
||||
case SampledUndefined:
|
||||
return "SampledUndefined"
|
||||
case SampledTrue:
|
||||
return "SampledTrue"
|
||||
default:
|
||||
return fmt.Sprintf("SampledInvalid(%d)", s)
|
||||
}
|
||||
}
|
||||
|
||||
// Bool returns true if the sample decision is SampledTrue, false otherwise.
|
||||
func (s Sampled) Bool() bool {
|
||||
return s == SampledTrue
|
||||
}
|
||||
|
||||
// A SpanOption is a function that can modify the properties of a span.
|
||||
type SpanOption func(s *Span)
|
||||
|
||||
// The TransactionName option sets the name of the current transaction.
|
||||
//
|
||||
// A span tree has a single transaction name, therefore using this option when
|
||||
// starting a span affects the span tree as a whole, potentially overwriting a
|
||||
// name set previously.
|
||||
func TransactionName(name string) SpanOption {
|
||||
return func(s *Span) {
|
||||
hubFromContext(s.Context()).Scope().SetTransaction(name)
|
||||
}
|
||||
}
|
||||
|
||||
// ContinueFromRequest returns a span option that updates the span to continue
|
||||
// an existing trace. If it cannot detect an existing trace in the request, the
|
||||
// span will be left unchanged.
|
||||
func ContinueFromRequest(r *http.Request) SpanOption {
|
||||
return func(s *Span) {
|
||||
trace := r.Header.Get("sentry-trace")
|
||||
if trace == "" {
|
||||
return
|
||||
}
|
||||
s.updateFromSentryTrace([]byte(trace))
|
||||
}
|
||||
}
|
||||
|
||||
// spanContextKey is used to store span values in contexts.
|
||||
type spanContextKey struct{}
|
||||
|
||||
// TransactionFromContext returns the root span of the current transaction. It
|
||||
// returns nil if no transaction is tracked in the context.
|
||||
func TransactionFromContext(ctx context.Context) *Span {
|
||||
if span, ok := ctx.Value(spanContextKey{}).(*Span); ok {
|
||||
return span.recorder.root()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// spanFromContext returns the last span stored in the context or a dummy
|
||||
// non-nil span.
|
||||
//
|
||||
// TODO(tracing): consider exporting this. Without this, users cannot retrieve a
|
||||
// span from a context since spanContextKey is not exported.
|
||||
//
|
||||
// This can be added retroactively, and in the meantime think better whether it
|
||||
// should return nil (like GetHubFromContext), always non-nil (like
|
||||
// HubFromContext), or both: two exported functions.
|
||||
//
|
||||
// Note the equivalence:
|
||||
//
|
||||
// SpanFromContext(ctx).StartChild(...) === StartSpan(ctx, ...)
|
||||
//
|
||||
// So we don't aim spanFromContext at creating spans, but mutating existing
|
||||
// spans that you'd have no access otherwise (because it was created in code you
|
||||
// do not control, for example SDK auto-instrumentation).
|
||||
//
|
||||
// For now we provide TransactionFromContext, which solves the more common case
|
||||
// of setting tags, etc, on the current transaction.
|
||||
func spanFromContext(ctx context.Context) *Span {
|
||||
if span, ok := ctx.Value(spanContextKey{}).(*Span); ok {
|
||||
return span
|
||||
}
|
||||
return nil
|
||||
}
|
||||
86
vendor/github.com/getsentry/sentry-go/transport.go
сгенерированный
поставляемый
86
vendor/github.com/getsentry/sentry-go/transport.go
сгенерированный
поставляемый
@@ -49,6 +49,8 @@ func getTLSConfig(options ClientOptions) *tls.Config {
|
||||
}
|
||||
|
||||
func retryAfter(now time.Time, r *http.Response) time.Duration {
|
||||
// TODO(tracing): handle x-sentry-rate-limits, separate rate limiting
|
||||
// per data type (error event, transaction, etc).
|
||||
retryAfterHeader := r.Header["Retry-After"]
|
||||
|
||||
if retryAfterHeader == nil {
|
||||
@@ -72,7 +74,7 @@ func getRequestBodyFromEvent(event *Event) []byte {
|
||||
return body
|
||||
}
|
||||
|
||||
partialMarshallMessage := fmt.Sprintf("Could not encode original event as JSON. "+
|
||||
msg := fmt.Sprintf("Could not encode original event as JSON. "+
|
||||
"Succeeded by removing Breadcrumbs, Contexts and Extra. "+
|
||||
"Please verify the data you attach to the scope. "+
|
||||
"Error: %s", err)
|
||||
@@ -80,54 +82,76 @@ func getRequestBodyFromEvent(event *Event) []byte {
|
||||
event.Breadcrumbs = nil
|
||||
event.Contexts = nil
|
||||
event.Extra = map[string]interface{}{
|
||||
"info": partialMarshallMessage,
|
||||
"info": msg,
|
||||
}
|
||||
body, err = json.Marshal(event)
|
||||
if err == nil {
|
||||
Logger.Println(partialMarshallMessage)
|
||||
Logger.Println(msg)
|
||||
return body
|
||||
}
|
||||
|
||||
// This should _only_ happen when Event.Exception[0].Stacktrace.Frames[0].Vars is unserializable
|
||||
// Which won't ever happen, as we don't use it now (although it's the part of public interface accepted by Sentry)
|
||||
// Juuust in case something, somehow goes utterly wrong.
|
||||
Logger.Println("Event couldn't be marshalled, even with stripped contextual data. Skipping delivery. " +
|
||||
Logger.Println("Event couldn't be marshaled, even with stripped contextual data. Skipping delivery. " +
|
||||
"Please notify the SDK owners with possibly broken payload.")
|
||||
return nil
|
||||
}
|
||||
|
||||
func getEnvelopeFromBody(body []byte, now time.Time) *bytes.Buffer {
|
||||
func transactionEnvelopeFromBody(eventID EventID, sentAt time.Time, body json.RawMessage) (*bytes.Buffer, error) {
|
||||
var b bytes.Buffer
|
||||
fmt.Fprintf(&b, `{"sent_at":"%s"}`, now.UTC().Format(time.RFC3339Nano))
|
||||
fmt.Fprint(&b, "\n", `{"type":"transaction"}`, "\n")
|
||||
b.Write(body)
|
||||
return &b
|
||||
enc := json.NewEncoder(&b)
|
||||
// envelope header
|
||||
err := enc.Encode(struct {
|
||||
EventID EventID `json:"event_id"`
|
||||
SentAt time.Time `json:"sent_at"`
|
||||
}{
|
||||
EventID: eventID,
|
||||
SentAt: sentAt,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// item header
|
||||
err = enc.Encode(struct {
|
||||
Type string `json:"type"`
|
||||
Length int `json:"length"`
|
||||
}{
|
||||
Type: transactionType,
|
||||
Length: len(body),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// payload
|
||||
err = enc.Encode(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &b, nil
|
||||
}
|
||||
|
||||
func getRequestFromEvent(event *Event, dsn *Dsn) (*http.Request, error) {
|
||||
body := getRequestBodyFromEvent(event)
|
||||
if body == nil {
|
||||
return nil, errors.New("event could not be marshalled")
|
||||
return nil, errors.New("event could not be marshaled")
|
||||
}
|
||||
|
||||
if event.Type == transactionType {
|
||||
env := getEnvelopeFromBody(body, time.Now())
|
||||
request, _ := http.NewRequest(
|
||||
b, err := transactionEnvelopeFromBody(event.EventID, time.Now(), body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return http.NewRequest(
|
||||
http.MethodPost,
|
||||
dsn.EnvelopeAPIURL().String(),
|
||||
env,
|
||||
b,
|
||||
)
|
||||
|
||||
return request, nil
|
||||
}
|
||||
|
||||
request, _ := http.NewRequest(
|
||||
return http.NewRequest(
|
||||
http.MethodPost,
|
||||
dsn.StoreAPIURL().String(),
|
||||
bytes.NewBuffer(body),
|
||||
bytes.NewReader(body),
|
||||
)
|
||||
|
||||
return request, nil
|
||||
}
|
||||
|
||||
// ================================
|
||||
@@ -249,9 +273,15 @@ func (t *HTTPTransport) SendEvent(event *Event) {
|
||||
|
||||
select {
|
||||
case b.items <- request:
|
||||
var eventType string
|
||||
if event.Type == transactionType {
|
||||
eventType = "transaction"
|
||||
} else {
|
||||
eventType = fmt.Sprintf("%s event", event.Level)
|
||||
}
|
||||
Logger.Printf(
|
||||
"Sending %s event [%s] to %s project: %d\n",
|
||||
event.Level,
|
||||
"Sending %s [%s] to %s project: %d",
|
||||
eventType,
|
||||
event.EventID,
|
||||
t.dsn.host,
|
||||
t.dsn.projectID,
|
||||
@@ -427,9 +457,15 @@ func (t *HTTPSyncTransport) SendEvent(event *Event) {
|
||||
request.Header.Set(headerKey, headerValue)
|
||||
}
|
||||
|
||||
var eventType string
|
||||
if event.Type == transactionType {
|
||||
eventType = "transaction"
|
||||
} else {
|
||||
eventType = fmt.Sprintf("%s event", event.Level)
|
||||
}
|
||||
Logger.Printf(
|
||||
"Sending %s event [%s] to %s project: %d\n",
|
||||
event.Level,
|
||||
"Sending %s [%s] to %s project: %d",
|
||||
eventType,
|
||||
event.EventID,
|
||||
t.dsn.host,
|
||||
t.dsn.projectID,
|
||||
|
||||
17
vendor/github.com/getsentry/sentry-go/util.go
сгенерированный
поставляемый
17
vendor/github.com/getsentry/sentry-go/util.go
сгенерированный
поставляемый
@@ -5,13 +5,14 @@ import (
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"time"
|
||||
)
|
||||
|
||||
func uuid() string {
|
||||
id := make([]byte, 16)
|
||||
_, _ = io.ReadFull(rand.Reader, id)
|
||||
// Prefer rand.Read over rand.Reader, see https://go-review.googlesource.com/c/go/+/272326/.
|
||||
_, _ = rand.Read(id)
|
||||
id[6] &= 0x0F // clear version
|
||||
id[6] |= 0x40 // set version to 4 (random uuid)
|
||||
id[8] &= 0x3F // clear variant
|
||||
@@ -20,11 +21,15 @@ func uuid() string {
|
||||
}
|
||||
|
||||
func fileExists(fileName string) bool {
|
||||
if _, err := os.Stat(fileName); err != nil {
|
||||
return false
|
||||
}
|
||||
_, err := os.Stat(fileName)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
return true
|
||||
// monotonicTimeSince replaces uses of time.Now() to take into account the
|
||||
// monotonic clock reading stored in start, such that duration = end - start is
|
||||
// unaffected by changes in the system wall clock.
|
||||
func monotonicTimeSince(start time.Time) (end time.Time) {
|
||||
return start.Add(time.Since(start))
|
||||
}
|
||||
|
||||
//nolint: deadcode, unused
|
||||
|
||||
Ссылка в новой задаче
Block a user