1
0
mirror of https://github.com/imgproxy/imgproxy.git synced 2025-02-02 11:34:20 +02:00

Forgotten vendor

This commit is contained in:
DarthSim 2019-08-19 18:10:48 +06:00
parent 12b59c3796
commit f1f9a355c7
49 changed files with 3304 additions and 6751 deletions

2
go.mod
View File

@ -11,7 +11,7 @@ require (
github.com/bugsnag/bugsnag-go v1.4.0
github.com/bugsnag/panicwrap v1.2.0 // indirect
github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261 // indirect
github.com/getsentry/raven-go v0.2.0
github.com/getsentry/raven-go v0.2.0 // indirect
github.com/getsentry/sentry-go v0.2.1
github.com/go-ole/go-ole v1.2.2 // indirect
github.com/gofrs/uuid v3.2.0+incompatible // indirect

View File

@ -1,3 +0,0 @@
This Source Code Form is subject to the terms of the Mozilla Public License,
v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
one at http://mozilla.org/MPL/2.0/.

View File

@ -1,60 +0,0 @@
# GoCertifi: SSL Certificates for Golang
This Go package contains a CA bundle that you can reference in your Go code.
This is useful for systems that do not have CA bundles that Golang can find
itself, or where a uniform set of CAs is valuable.
This is the same CA bundle that ships with the
[Python Requests](https://github.com/kennethreitz/requests) library, and is a
Golang specific port of [certifi](https://github.com/kennethreitz/certifi). The
CA bundle is derived from Mozilla's canonical set.
## Usage
You can use the `gocertifi` package as follows:
```go
import "github.com/certifi/gocertifi"
cert_pool, err := gocertifi.CACerts()
```
You can use the returned `*x509.CertPool` as part of an HTTP transport, for example:
```go
import (
"net/http"
"crypto/tls"
)
// Setup an HTTP client with a custom transport
transport := &http.Transport{
TLSClientConfig: &tls.Config{RootCAs: cert_pool},
}
client := &http.Client{Transport: transport}
// Make an HTTP request using our custom transport
resp, err := client.Get("https://example.com")
```
## Detailed Documentation
Import as follows:
```go
import "github.com/certifi/gocertifi"
```
### Errors
```go
var ErrParseFailed = errors.New("gocertifi: error when parsing certificates")
```
### Functions
```go
func CACerts() (*x509.CertPool, error)
```
CACerts builds an X.509 certificate pool containing the Mozilla CA Certificate
bundle. Returns nil on error along with an appropriate error code.

File diff suppressed because it is too large Load Diff

View File

@ -1,20 +0,0 @@
from invoke import task
import requests
@task
def update(ctx):
r = requests.get('https://mkcert.org/generate/')
r.raise_for_status()
certs = r.content
with open('certifi.go', 'rb') as f:
file = f.read()
file = file.split('`\n')
assert len(file) == 3
file[1] = certs
ctx.run("rm certifi.go")
with open('certifi.go', 'wb') as f:
f.write('`\n'.join(file))

View File

@ -1 +0,0 @@
.git

View File

@ -1,5 +0,0 @@
*.test
*.out
example/example
/xunit.xml
/coverage.xml

View File

View File

@ -1,41 +0,0 @@
sudo: false
language: go
go:
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
before_install:
- go install -race std
- go get golang.org/x/tools/cmd/cover
- go get github.com/tebeka/go2xunit
- go get github.com/t-yuki/gocover-cobertura
- go get -v ./...
script:
- go test -v -race ./... | tee gotest.out
- $GOPATH/bin/go2xunit -fail -input gotest.out -output xunit.xml
- go test -v -coverprofile=coverage.txt -covermode count .
- $GOPATH/bin/gocover-cobertura < coverage.txt > coverage.xml
after_script:
- npm install -g @zeus-ci/cli
- zeus upload -t "application/x-cobertura+xml" coverage.xml
- zeus upload -t "application/x-xunit+xml" xunit.xml
matrix:
allow_failures:
- go: tip
notifications:
webhooks:
urls:
- https://zeus.ci/hooks/cd949996-d30a-11e8-ba53-0a580a28042d/public/provider/travis/webhook
on_success: always
on_failure: always
on_start: always
on_cancel: always
on_error: always

View File

@ -1,28 +0,0 @@
Copyright (c) 2013 Apollic Software, LLC. All rights reserved.
Copyright (c) 2015 Functional Software, Inc. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Apollic Software, LLC nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,19 +0,0 @@
# raven
[![Build Status](https://api.travis-ci.org/getsentry/raven-go.svg?branch=master)](https://travis-ci.org/getsentry/raven-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/raven-go)](https://goreportcard.com/report/github.com/getsentry/raven-go)
[![GoDoc](https://godoc.org/github.com/getsentry/raven-go?status.svg)](https://godoc.org/github.com/getsentry/raven-go)
raven is the official Go SDK for the [Sentry](https://github.com/getsentry/sentry)
event/error logging system.
- [**API Documentation**](https://godoc.org/github.com/getsentry/raven-go)
- [**Usage and Examples**](https://docs.sentry.io/clients/go/)
## Installation
```text
go get github.com/getsentry/raven-go
```
Note: Go 1.7 and newer are supported.

View File

@ -1,977 +0,0 @@
// Package raven implements a client for the Sentry error logging service.
package raven
import (
"bytes"
"compress/zlib"
"crypto/rand"
"crypto/tls"
"encoding/base64"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"io"
"io/ioutil"
"log"
mrand "math/rand"
"net/http"
"net/url"
"os"
"regexp"
"runtime"
"strings"
"sync"
"time"
"github.com/certifi/gocertifi"
pkgErrors "github.com/pkg/errors"
)
const (
userAgent = "raven-go/1.0"
timestampFormat = `"2006-01-02T15:04:05.00"`
)
var (
ErrPacketDropped = errors.New("raven: packet dropped")
ErrUnableToUnmarshalJSON = errors.New("raven: unable to unmarshal JSON")
ErrMissingUser = errors.New("raven: dsn missing public key and/or password")
ErrMissingProjectID = errors.New("raven: dsn missing project id")
ErrInvalidSampleRate = errors.New("raven: sample rate should be between 0 and 1")
)
type Severity string
// http://docs.python.org/2/howto/logging.html#logging-levels
const (
DEBUG = Severity("debug")
INFO = Severity("info")
WARNING = Severity("warning")
ERROR = Severity("error")
FATAL = Severity("fatal")
)
type Timestamp time.Time
func (t Timestamp) MarshalJSON() ([]byte, error) {
return []byte(time.Time(t).UTC().Format(timestampFormat)), nil
}
func (timestamp *Timestamp) UnmarshalJSON(data []byte) error {
t, err := time.Parse(timestampFormat, string(data))
if err != nil {
return err
}
*timestamp = Timestamp(t)
return nil
}
func (timestamp Timestamp) Format(format string) string {
t := time.Time(timestamp)
return t.Format(format)
}
// An Interface is a Sentry interface that will be serialized as JSON.
// It must implement json.Marshaler or use json struct tags.
type Interface interface {
// The Sentry class name. Example: sentry.interfaces.Stacktrace
Class() string
}
type Culpriter interface {
Culprit() string
}
type Transport interface {
Send(url, authHeader string, packet *Packet) error
}
type Extra map[string]interface{}
type outgoingPacket struct {
packet *Packet
ch chan error
}
type Tag struct {
Key string
Value string
}
type Tags []Tag
func (tag *Tag) MarshalJSON() ([]byte, error) {
return json.Marshal([2]string{tag.Key, tag.Value})
}
func (t *Tag) UnmarshalJSON(data []byte) error {
var tag [2]string
if err := json.Unmarshal(data, &tag); err != nil {
return err
}
*t = Tag{tag[0], tag[1]}
return nil
}
func (t *Tags) UnmarshalJSON(data []byte) error {
var tags []Tag
switch data[0] {
case '[':
// Unmarshal into []Tag
if err := json.Unmarshal(data, &tags); err != nil {
return err
}
case '{':
// Unmarshal into map[string]string
tagMap := make(map[string]string)
if err := json.Unmarshal(data, &tagMap); err != nil {
return err
}
// Convert to []Tag
for k, v := range tagMap {
tags = append(tags, Tag{k, v})
}
default:
return ErrUnableToUnmarshalJSON
}
*t = tags
return nil
}
// https://docs.getsentry.com/hosted/clientdev/#building-the-json-packet
type Packet struct {
// Required
Message string `json:"message"`
// Required, set automatically by Client.Send/Report via Packet.Init if blank
EventID string `json:"event_id"`
Project string `json:"project"`
Timestamp Timestamp `json:"timestamp"`
Level Severity `json:"level"`
Logger string `json:"logger"`
// Optional
Platform string `json:"platform,omitempty"`
Culprit string `json:"culprit,omitempty"`
ServerName string `json:"server_name,omitempty"`
Release string `json:"release,omitempty"`
Environment string `json:"environment,omitempty"`
Tags Tags `json:"tags,omitempty"`
Modules map[string]string `json:"modules,omitempty"`
Fingerprint []string `json:"fingerprint,omitempty"`
Extra Extra `json:"extra,omitempty"`
Interfaces []Interface `json:"-"`
}
// NewPacket constructs a packet with the specified message and interfaces.
func NewPacket(message string, interfaces ...Interface) *Packet {
extra := Extra{}
setExtraDefaults(extra)
return &Packet{
Message: message,
Interfaces: interfaces,
Extra: extra,
}
}
// NewPacketWithExtra constructs a packet with the specified message, extra information, and interfaces.
func NewPacketWithExtra(message string, extra Extra, interfaces ...Interface) *Packet {
if extra == nil {
extra = Extra{}
}
setExtraDefaults(extra)
return &Packet{
Message: message,
Interfaces: interfaces,
Extra: extra,
}
}
func setExtraDefaults(extra Extra) Extra {
extra["runtime.Version"] = runtime.Version()
extra["runtime.NumCPU"] = runtime.NumCPU()
extra["runtime.GOMAXPROCS"] = runtime.GOMAXPROCS(0) // 0 just returns the current value
extra["runtime.NumGoroutine"] = runtime.NumGoroutine()
return extra
}
// Init initializes required fields in a packet. It is typically called by
// Client.Send/Report automatically.
func (packet *Packet) Init(project string) error {
if packet.Project == "" {
packet.Project = project
}
if packet.EventID == "" {
var err error
packet.EventID, err = uuid()
if err != nil {
return err
}
}
if time.Time(packet.Timestamp).IsZero() {
packet.Timestamp = Timestamp(time.Now())
}
if packet.Level == "" {
packet.Level = ERROR
}
if packet.Logger == "" {
packet.Logger = "root"
}
if packet.ServerName == "" {
packet.ServerName = hostname
}
if packet.Platform == "" {
packet.Platform = "go"
}
if packet.Culprit == "" {
for _, inter := range packet.Interfaces {
if c, ok := inter.(Culpriter); ok {
packet.Culprit = c.Culprit()
if packet.Culprit != "" {
break
}
}
}
}
return nil
}
func (packet *Packet) AddTags(tags map[string]string) {
for k, v := range tags {
packet.Tags = append(packet.Tags, Tag{k, v})
}
}
func uuid() (string, error) {
id := make([]byte, 16)
_, err := io.ReadFull(rand.Reader, id)
if err != nil {
return "", err
}
id[6] &= 0x0F // clear version
id[6] |= 0x40 // set version to 4 (random uuid)
id[8] &= 0x3F // clear variant
id[8] |= 0x80 // set to IETF variant
return hex.EncodeToString(id), nil
}
func (packet *Packet) JSON() ([]byte, error) {
packetJSON, err := json.Marshal(packet)
if err != nil {
return nil, err
}
interfaces := make(map[string]Interface, len(packet.Interfaces))
for _, inter := range packet.Interfaces {
if inter != nil {
interfaces[inter.Class()] = inter
}
}
if len(interfaces) > 0 {
interfaceJSON, err := json.Marshal(interfaces)
if err != nil {
return nil, err
}
packetJSON[len(packetJSON)-1] = ','
packetJSON = append(packetJSON, interfaceJSON[1:]...)
}
return packetJSON, nil
}
type context struct {
user *User
http *Http
tags map[string]string
}
func (c *context) setUser(u *User) { c.user = u }
func (c *context) setHttp(h *Http) { c.http = h }
func (c *context) setTags(t map[string]string) {
if c.tags == nil {
c.tags = make(map[string]string)
}
for k, v := range t {
c.tags[k] = v
}
}
func (c *context) clear() {
c.user = nil
c.http = nil
c.tags = nil
}
// Return a list of interfaces to be used in appending with the rest
func (c *context) interfaces() []Interface {
len, i := 0, 0
if c.user != nil {
len++
}
if c.http != nil {
len++
}
interfaces := make([]Interface, len)
if c.user != nil {
interfaces[i] = c.user
i++
}
if c.http != nil {
interfaces[i] = c.http
i++
}
return interfaces
}
// The maximum number of packets that will be buffered waiting to be delivered.
// Packets will be dropped if the buffer is full. Used by NewClient.
var MaxQueueBuffer = 100
func newTransport() Transport {
t := &HTTPTransport{}
rootCAs, err := gocertifi.CACerts()
if err != nil {
log.Println("raven: failed to load root TLS certificates:", err)
} else {
t.Client = &http.Client{
Transport: &http.Transport{
Proxy: http.ProxyFromEnvironment,
TLSClientConfig: &tls.Config{RootCAs: rootCAs},
},
}
}
return t
}
func newClient(tags map[string]string) *Client {
client := &Client{
Transport: newTransport(),
Tags: tags,
context: &context{},
sampleRate: 1.0,
queue: make(chan *outgoingPacket, MaxQueueBuffer),
}
client.SetDSN(os.Getenv("SENTRY_DSN"))
client.SetRelease(os.Getenv("SENTRY_RELEASE"))
client.SetEnvironment(os.Getenv("SENTRY_ENVIRONMENT"))
return client
}
// New constructs a new Sentry client instance
func New(dsn string) (*Client, error) {
client := newClient(nil)
return client, client.SetDSN(dsn)
}
// NewWithTags constructs a new Sentry client instance with default tags.
func NewWithTags(dsn string, tags map[string]string) (*Client, error) {
client := newClient(tags)
return client, client.SetDSN(dsn)
}
// NewClient constructs a Sentry client and spawns a background goroutine to
// handle packets sent by Client.Report.
//
// Deprecated: use New and NewWithTags instead
func NewClient(dsn string, tags map[string]string) (*Client, error) {
client := newClient(tags)
return client, client.SetDSN(dsn)
}
// Client encapsulates a connection to a Sentry server. It must be initialized
// by calling NewClient. Modification of fields concurrently with Send or after
// calling Report for the first time is not thread-safe.
type Client struct {
Tags map[string]string
Transport Transport
// DropHandler is called when a packet is dropped because the buffer is full.
DropHandler func(*Packet)
// Context that will get appending to all packets
context *context
mu sync.RWMutex
url string
projectID string
authHeader string
release string
environment string
sampleRate float32
// default logger name (leave empty for 'root')
defaultLoggerName string
includePaths []string
ignoreErrorsRegexp *regexp.Regexp
queue chan *outgoingPacket
// A WaitGroup to keep track of all currently in-progress captures
// This is intended to be used with Client.Wait() to assure that
// all messages have been transported before exiting the process.
wg sync.WaitGroup
// A Once to track only starting up the background worker once
start sync.Once
}
// Initialize a default *Client instance
var DefaultClient = newClient(nil)
func (c *Client) SetIgnoreErrors(errs []string) error {
joinedRegexp := strings.Join(errs, "|")
r, err := regexp.Compile(joinedRegexp)
if err != nil {
return fmt.Errorf("failed to compile regexp %q for %q: %v", joinedRegexp, errs, err)
}
c.mu.Lock()
c.ignoreErrorsRegexp = r
c.mu.Unlock()
return nil
}
func (c *Client) shouldExcludeErr(errStr string) bool {
c.mu.RLock()
defer c.mu.RUnlock()
return c.ignoreErrorsRegexp != nil && c.ignoreErrorsRegexp.MatchString(errStr)
}
func SetIgnoreErrors(errs ...string) error {
return DefaultClient.SetIgnoreErrors(errs)
}
// SetDSN updates a client with a new DSN. It safe to call after and
// concurrently with calls to Report and Send.
func (client *Client) SetDSN(dsn string) error {
if dsn == "" {
return nil
}
client.mu.Lock()
defer client.mu.Unlock()
uri, err := url.Parse(dsn)
if err != nil {
return err
}
if uri.User == nil {
return ErrMissingUser
}
publicKey := uri.User.Username()
secretKey, hasSecretKey := uri.User.Password()
uri.User = nil
if idx := strings.LastIndex(uri.Path, "/"); idx != -1 {
client.projectID = uri.Path[idx+1:]
uri.Path = uri.Path[:idx+1] + "api/" + client.projectID + "/store/"
}
if client.projectID == "" {
return ErrMissingProjectID
}
client.url = uri.String()
if hasSecretKey {
client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s, sentry_secret=%s", publicKey, secretKey)
} else {
client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s", publicKey)
}
return nil
}
// Sets the DSN for the default *Client instance
func SetDSN(dsn string) error { return DefaultClient.SetDSN(dsn) }
// SetRelease sets the "release" tag.
func (client *Client) SetRelease(release string) {
client.mu.Lock()
defer client.mu.Unlock()
client.release = release
}
// SetEnvironment sets the "environment" tag.
func (client *Client) SetEnvironment(environment string) {
client.mu.Lock()
defer client.mu.Unlock()
client.environment = environment
}
// SetDefaultLoggerName sets the default logger name.
func (client *Client) SetDefaultLoggerName(name string) {
client.mu.Lock()
defer client.mu.Unlock()
client.defaultLoggerName = name
}
// SetSampleRate sets how much sampling we want on client side
func (client *Client) SetSampleRate(rate float32) error {
client.mu.Lock()
defer client.mu.Unlock()
if rate < 0 || rate > 1 {
return ErrInvalidSampleRate
}
client.sampleRate = rate
return nil
}
// SetRelease sets the "release" tag on the default *Client
func SetRelease(release string) { DefaultClient.SetRelease(release) }
// SetEnvironment sets the "environment" tag on the default *Client
func SetEnvironment(environment string) { DefaultClient.SetEnvironment(environment) }
// SetDefaultLoggerName sets the "defaultLoggerName" on the default *Client
func SetDefaultLoggerName(name string) {
DefaultClient.SetDefaultLoggerName(name)
}
// SetSampleRate sets the "sample rate" on the degault *Client
func SetSampleRate(rate float32) error { return DefaultClient.SetSampleRate(rate) }
func (client *Client) worker() {
for outgoingPacket := range client.queue {
client.mu.RLock()
url, authHeader := client.url, client.authHeader
client.mu.RUnlock()
outgoingPacket.ch <- client.Transport.Send(url, authHeader, outgoingPacket.packet)
client.wg.Done()
}
}
// Capture asynchronously delivers a packet to the Sentry server. It is a no-op
// when client is nil. A channel is provided if it is important to check for a
// send's success.
func (client *Client) Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
ch = make(chan error, 1)
if client == nil {
// return a chan that always returns nil when the caller receives from it
close(ch)
return
}
if client.sampleRate < 1.0 && mrand.Float32() > client.sampleRate {
return
}
if packet == nil {
close(ch)
return
}
if client.shouldExcludeErr(packet.Message) {
return
}
// Keep track of all running Captures so that we can wait for them all to finish
// *Must* call client.wg.Done() on any path that indicates that an event was
// finished being acted upon, whether success or failure
client.wg.Add(1)
// Merge capture tags and client tags
packet.AddTags(captureTags)
packet.AddTags(client.Tags)
// Initialize any required packet fields
client.mu.RLock()
packet.AddTags(client.context.tags)
projectID := client.projectID
release := client.release
environment := client.environment
defaultLoggerName := client.defaultLoggerName
client.mu.RUnlock()
// set the global logger name on the packet if we must
if packet.Logger == "" && defaultLoggerName != "" {
packet.Logger = defaultLoggerName
}
err := packet.Init(projectID)
if err != nil {
ch <- err
client.wg.Done()
return
}
if packet.Release == "" {
packet.Release = release
}
if packet.Environment == "" {
packet.Environment = environment
}
outgoingPacket := &outgoingPacket{packet, ch}
// Lazily start background worker until we
// do our first write into the queue.
client.start.Do(func() {
go client.worker()
})
select {
case client.queue <- outgoingPacket:
default:
// Send would block, drop the packet
if client.DropHandler != nil {
client.DropHandler(packet)
}
ch <- ErrPacketDropped
client.wg.Done()
}
return packet.EventID, ch
}
// Capture asynchronously delivers a packet to the Sentry server with the default *Client.
// It is a no-op when client is nil. A channel is provided if it is important to check for a
// send's success.
func Capture(packet *Packet, captureTags map[string]string) (eventID string, ch chan error) {
return DefaultClient.Capture(packet, captureTags)
}
// CaptureMessage formats and delivers a string message to the Sentry server.
func (client *Client) CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}
if client.shouldExcludeErr(message) {
return ""
}
packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
eventID, _ := client.Capture(packet, tags)
return eventID
}
// CaptureMessage formats and delivers a string message to the Sentry server with the default *Client
func CaptureMessage(message string, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureMessage(message, tags, interfaces...)
}
// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
func (client *Client) CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}
if client.shouldExcludeErr(message) {
return ""
}
packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
eventID, ch := client.Capture(packet, tags)
if eventID != "" {
<-ch
}
return eventID
}
// CaptureMessageAndWait is identical to CaptureMessage except it blocks and waits for the message to be sent.
func CaptureMessageAndWait(message string, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureMessageAndWait(message, tags, interfaces...)
}
// CaptureErrors formats and delivers an error to the Sentry server.
// Adds a stacktrace to the packet, excluding the call to this method.
func (client *Client) CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}
if err == nil {
return ""
}
if client.shouldExcludeErr(err.Error()) {
return ""
}
extra := extractExtra(err)
cause := pkgErrors.Cause(err)
packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
eventID, _ := client.Capture(packet, tags)
return eventID
}
// CaptureErrors formats and delivers an error to the Sentry server using the default *Client.
// Adds a stacktrace to the packet, excluding the call to this method.
func CaptureError(err error, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureError(err, tags, interfaces...)
}
// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func (client *Client) CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
if client == nil {
return ""
}
if client.shouldExcludeErr(err.Error()) {
return ""
}
extra := extractExtra(err)
cause := pkgErrors.Cause(err)
packet := NewPacketWithExtra(err.Error(), extra, append(append(interfaces, client.context.interfaces()...), NewException(cause, GetOrNewStacktrace(cause, 1, 3, client.includePaths)))...)
eventID, ch := client.Capture(packet, tags)
if eventID != "" {
<-ch
}
return eventID
}
// CaptureErrorAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func CaptureErrorAndWait(err error, tags map[string]string, interfaces ...Interface) string {
return DefaultClient.CaptureErrorAndWait(err, tags, interfaces...)
}
// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
// If an error is captured, both the error and the reported Sentry error ID are returned.
func (client *Client) CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
// Note: This doesn't need to check for client, because we still want to go through the defer/recover path
// Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
// *Packet just to be thrown away, this should not be the normal case. Could be refactored to
// be completely noop though if we cared.
defer func() {
var packet *Packet
err = recover()
switch rval := err.(type) {
case nil:
return
case error:
if client.shouldExcludeErr(rval.Error()) {
return
}
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
default:
rvalStr := fmt.Sprint(rval)
if client.shouldExcludeErr(rvalStr) {
return
}
packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
}
errorID, _ = client.Capture(packet, tags)
}()
f()
return
}
// CapturePanic calls f and then recovers and reports a panic to the Sentry server if it occurs.
// If an error is captured, both the error and the reported Sentry error ID are returned.
func CapturePanic(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
return DefaultClient.CapturePanic(f, tags, interfaces...)
}
// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func (client *Client) CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (err interface{}, errorID string) {
// Note: This doesn't need to check for client, because we still want to go through the defer/recover path
// Down the line, Capture will be noop'd, so while this does a _tiny_ bit of overhead constructing the
// *Packet just to be thrown away, this should not be the normal case. Could be refactored to
// be completely noop though if we cared.
defer func() {
var packet *Packet
err = recover()
switch rval := err.(type) {
case nil:
return
case error:
if client.shouldExcludeErr(rval.Error()) {
return
}
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
default:
rvalStr := fmt.Sprint(rval)
if client.shouldExcludeErr(rvalStr) {
return
}
packet = NewPacket(rvalStr, append(append(interfaces, client.context.interfaces()...), NewException(errors.New(rvalStr), NewStacktrace(2, 3, client.includePaths)))...)
}
var ch chan error
errorID, ch = client.Capture(packet, tags)
if errorID != "" {
<-ch
}
}()
f()
return
}
// CapturePanicAndWait is identical to CaptureError, except it blocks and assures that the event was sent
func CapturePanicAndWait(f func(), tags map[string]string, interfaces ...Interface) (interface{}, string) {
return DefaultClient.CapturePanicAndWait(f, tags, interfaces...)
}
func (client *Client) Close() {
close(client.queue)
}
func Close() { DefaultClient.Close() }
// Wait blocks and waits for all events to finish being sent to Sentry server
func (client *Client) Wait() {
client.wg.Wait()
}
// Wait blocks and waits for all events to finish being sent to Sentry server
func Wait() { DefaultClient.Wait() }
func (client *Client) URL() string {
client.mu.RLock()
defer client.mu.RUnlock()
return client.url
}
func URL() string { return DefaultClient.URL() }
func (client *Client) ProjectID() string {
client.mu.RLock()
defer client.mu.RUnlock()
return client.projectID
}
func ProjectID() string { return DefaultClient.ProjectID() }
func (client *Client) Release() string {
client.mu.RLock()
defer client.mu.RUnlock()
return client.release
}
func Release() string { return DefaultClient.Release() }
func IncludePaths() []string { return DefaultClient.IncludePaths() }
func (client *Client) IncludePaths() []string {
client.mu.RLock()
defer client.mu.RUnlock()
return client.includePaths
}
func SetIncludePaths(p []string) { DefaultClient.SetIncludePaths(p) }
func (client *Client) SetIncludePaths(p []string) {
client.mu.Lock()
defer client.mu.Unlock()
client.includePaths = p
}
func (c *Client) SetUserContext(u *User) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setUser(u)
}
func (c *Client) SetHttpContext(h *Http) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setHttp(h)
}
func (c *Client) SetTagsContext(t map[string]string) {
c.mu.Lock()
defer c.mu.Unlock()
c.context.setTags(t)
}
func (c *Client) ClearContext() {
c.mu.Lock()
defer c.mu.Unlock()
c.context.clear()
}
func SetUserContext(u *User) { DefaultClient.SetUserContext(u) }
func SetHttpContext(h *Http) { DefaultClient.SetHttpContext(h) }
func SetTagsContext(t map[string]string) { DefaultClient.SetTagsContext(t) }
func ClearContext() { DefaultClient.ClearContext() }
// HTTPTransport is the default transport, delivering packets to Sentry via the
// HTTP API.
type HTTPTransport struct {
*http.Client
}
func (t *HTTPTransport) Send(url, authHeader string, packet *Packet) error {
if url == "" {
return nil
}
body, contentType, err := serializedPacket(packet)
if err != nil {
return fmt.Errorf("error serializing packet: %v", err)
}
req, err := http.NewRequest("POST", url, body)
if err != nil {
return fmt.Errorf("can't create new request: %v", err)
}
req.Header.Set("X-Sentry-Auth", authHeader)
req.Header.Set("User-Agent", userAgent)
req.Header.Set("Content-Type", contentType)
res, err := t.Do(req)
if err != nil {
return err
}
io.Copy(ioutil.Discard, res.Body)
res.Body.Close()
if res.StatusCode != 200 {
return fmt.Errorf("raven: got http status %d - x-sentry-error: %s", res.StatusCode, res.Header.Get("X-Sentry-Error"))
}
return nil
}
func serializedPacket(packet *Packet) (io.Reader, string, error) {
packetJSON, err := packet.JSON()
if err != nil {
return nil, "", fmt.Errorf("error marshaling packet %+v to JSON: %v", packet, err)
}
// Only deflate/base64 the packet if it is bigger than 1KB, as there is
// overhead.
if len(packetJSON) > 1000 {
buf := &bytes.Buffer{}
b64 := base64.NewEncoder(base64.StdEncoding, buf)
deflate, _ := zlib.NewWriterLevel(b64, zlib.BestCompression)
deflate.Write(packetJSON)
deflate.Close()
b64.Close()
return buf, "application/octet-stream", nil
}
return bytes.NewReader(packetJSON), "application/json", nil
}
var hostname string
func init() {
hostname, _ = os.Hostname()
}

View File

@ -1,60 +0,0 @@
package raven
type causer interface {
Cause() error
}
type errWrappedWithExtra struct {
err error
extraInfo map[string]interface{}
}
func (ewx *errWrappedWithExtra) Error() string {
return ewx.err.Error()
}
func (ewx *errWrappedWithExtra) Cause() error {
return ewx.err
}
func (ewx *errWrappedWithExtra) ExtraInfo() Extra {
return ewx.extraInfo
}
// Adds extra data to an error before reporting to Sentry
func WrapWithExtra(err error, extraInfo map[string]interface{}) error {
return &errWrappedWithExtra{
err: err,
extraInfo: extraInfo,
}
}
type ErrWithExtra interface {
Error() string
Cause() error
ExtraInfo() Extra
}
// Iteratively fetches all the Extra data added to an error,
// and it's underlying errors. Extra data defined first is
// respected, and is not overridden when extracting.
func extractExtra(err error) Extra {
extra := Extra{}
currentErr := err
for currentErr != nil {
if errWithExtra, ok := currentErr.(ErrWithExtra); ok {
for k, v := range errWithExtra.ExtraInfo() {
extra[k] = v
}
}
if errWithCause, ok := currentErr.(causer); ok {
currentErr = errWithCause.Cause()
} else {
currentErr = nil
}
}
return extra
}

View File

@ -1,50 +0,0 @@
package raven
import (
"reflect"
"regexp"
)
var errorMsgPattern = regexp.MustCompile(`\A(\w+): (.+)\z`)
func NewException(err error, stacktrace *Stacktrace) *Exception {
msg := err.Error()
ex := &Exception{
Stacktrace: stacktrace,
Value: msg,
Type: reflect.TypeOf(err).String(),
}
if m := errorMsgPattern.FindStringSubmatch(msg); m != nil {
ex.Module, ex.Value = m[1], m[2]
}
return ex
}
// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
type Exception struct {
// Required
Value string `json:"value"`
// Optional
Type string `json:"type,omitempty"`
Module string `json:"module,omitempty"`
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
}
func (e *Exception) Class() string { return "exception" }
func (e *Exception) Culprit() string {
if e.Stacktrace == nil {
return ""
}
return e.Stacktrace.Culprit()
}
// Exceptions allows for chained errors
// https://docs.sentry.io/clientdev/interfaces/exception/
type Exceptions struct {
// Required
Values []*Exception `json:"values"`
}
func (es Exceptions) Class() string { return "exception" }

View File

@ -1,99 +0,0 @@
package raven
import (
"errors"
"fmt"
"net"
"net/http"
"net/url"
"runtime/debug"
"strings"
)
func NewHttp(req *http.Request) *Http {
proto := "http"
if req.TLS != nil || req.Header.Get("X-Forwarded-Proto") == "https" {
proto = "https"
}
h := &Http{
Method: req.Method,
Cookies: req.Header.Get("Cookie"),
Query: sanitizeQuery(req.URL.Query()).Encode(),
URL: proto + "://" + req.Host + req.URL.Path,
Headers: make(map[string]string, len(req.Header)),
}
if addr, port, err := net.SplitHostPort(req.RemoteAddr); err == nil {
h.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
}
for k, v := range req.Header {
h.Headers[k] = strings.Join(v, ",")
}
h.Headers["Host"] = req.Host
return h
}
var querySecretFields = []string{"password", "passphrase", "passwd", "secret"}
func sanitizeQuery(query url.Values) url.Values {
for _, keyword := range querySecretFields {
for field := range query {
if strings.Contains(field, keyword) {
query[field] = []string{"********"}
}
}
}
return query
}
// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type Http struct {
// Required
URL string `json:"url"`
Method string `json:"method"`
Query string `json:"query_string,omitempty"`
// Optional
Cookies string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Env map[string]string `json:"env,omitempty"`
// Must be either a string or map[string]string
Data interface{} `json:"data,omitempty"`
}
func (h *Http) Class() string { return "request" }
// Recovery handler to wrap the stdlib net/http Mux.
// Example:
// http.HandleFunc("/", raven.RecoveryHandler(func(w http.ResponseWriter, r *http.Request) {
// ...
// }))
func RecoveryHandler(handler func(http.ResponseWriter, *http.Request)) func(http.ResponseWriter, *http.Request) {
return Recoverer(http.HandlerFunc(handler)).ServeHTTP
}
// Recovery handler to wrap the stdlib net/http Mux.
// Example:
// mux := http.NewServeMux
// ...
// http.Handle("/", raven.Recoverer(mux))
func Recoverer(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if rval := recover(); rval != nil {
debug.PrintStack()
rvalStr := fmt.Sprint(rval)
var packet *Packet
if err, ok := rval.(error); ok {
packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), GetOrNewStacktrace(err, 2, 3, nil)), NewHttp(r))
} else {
packet = NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
}
Capture(packet, nil)
w.WriteHeader(http.StatusInternalServerError)
}
}()
handler.ServeHTTP(w, r)
})
}

View File

@ -1,49 +0,0 @@
package raven
// https://docs.getsentry.com/hosted/clientdev/interfaces/#message-interface
type Message struct {
// Required
Message string `json:"message"`
// Optional
Params []interface{} `json:"params,omitempty"`
}
func (m *Message) Class() string { return "logentry" }
// https://docs.getsentry.com/hosted/clientdev/interfaces/#template-interface
type Template struct {
// Required
Filename string `json:"filename"`
Lineno int `json:"lineno"`
ContextLine string `json:"context_line"`
// Optional
PreContext []string `json:"pre_context,omitempty"`
PostContext []string `json:"post_context,omitempty"`
AbsolutePath string `json:"abs_path,omitempty"`
}
func (t *Template) Class() string { return "template" }
// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type User struct {
// All fields are optional
ID string `json:"id,omitempty"`
Username string `json:"username,omitempty"`
Email string `json:"email,omitempty"`
IP string `json:"ip_address,omitempty"`
}
func (h *User) Class() string { return "user" }
// https://docs.getsentry.com/hosted/clientdev/interfaces/#context-interfaces
type Query struct {
// Required
Query string `json:"query"`
// Optional
Engine string `json:"engine,omitempty"`
}
func (q *Query) Class() string { return "query" }

View File

@ -1,4 +0,0 @@
#!/bin/bash
go test -race ./...
go test -cover ./...
go test -v ./...

View File

@ -1,277 +0,0 @@
// Copyright 2011 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Some code from the runtime/debug package of the Go standard library.
package raven
import (
"bytes"
"go/build"
"io/ioutil"
"path/filepath"
"runtime"
"strings"
"sync"
"github.com/pkg/errors"
)
// https://docs.getsentry.com/hosted/clientdev/interfaces/#failure-interfaces
type Stacktrace struct {
// Required
Frames []*StacktraceFrame `json:"frames"`
}
func (s *Stacktrace) Class() string { return "stacktrace" }
func (s *Stacktrace) Culprit() string {
for i := len(s.Frames) - 1; i >= 0; i-- {
frame := s.Frames[i]
if frame.InApp == true && frame.Module != "" && frame.Function != "" {
return frame.Module + "." + frame.Function
}
}
return ""
}
type StacktraceFrame struct {
// At least one required
Filename string `json:"filename,omitempty"`
Function string `json:"function,omitempty"`
Module string `json:"module,omitempty"`
// Optional
Lineno int `json:"lineno,omitempty"`
Colno int `json:"colno,omitempty"`
AbsolutePath string `json:"abs_path,omitempty"`
ContextLine string `json:"context_line,omitempty"`
PreContext []string `json:"pre_context,omitempty"`
PostContext []string `json:"post_context,omitempty"`
InApp bool `json:"in_app"`
}
// Try to get stacktrace from err as an interface of github.com/pkg/errors, or else NewStacktrace()
func GetOrNewStacktrace(err error, skip int, context int, appPackagePrefixes []string) *Stacktrace {
stacktracer, errHasStacktrace := err.(interface {
StackTrace() errors.StackTrace
})
if errHasStacktrace {
var frames []*StacktraceFrame
for _, f := range stacktracer.StackTrace() {
pc := uintptr(f) - 1
fn := runtime.FuncForPC(pc)
var fName string
var file string
var line int
if fn != nil {
file, line = fn.FileLine(pc)
fName = fn.Name()
} else {
file = "unknown"
fName = "unknown"
}
frame := NewStacktraceFrame(pc, fName, file, line, context, appPackagePrefixes)
if frame != nil {
frames = append([]*StacktraceFrame{frame}, frames...)
}
}
return &Stacktrace{Frames: frames}
} else {
return NewStacktrace(skip+1, context, appPackagePrefixes)
}
}
// Intialize and populate a new stacktrace, skipping skip frames.
//
// context is the number of surrounding lines that should be included for context.
// Setting context to 3 would try to get seven lines. Setting context to -1 returns
// one line with no surrounding context, and 0 returns no context.
//
// appPackagePrefixes is a list of prefixes used to check whether a package should
// be considered "in app".
func NewStacktrace(skip int, context int, appPackagePrefixes []string) *Stacktrace {
var frames []*StacktraceFrame
callerPcs := make([]uintptr, 100)
numCallers := runtime.Callers(skip+2, callerPcs)
// If there are no callers, the entire stacktrace is nil
if numCallers == 0 {
return nil
}
callersFrames := runtime.CallersFrames(callerPcs)
for {
fr, more := callersFrames.Next()
if fr.Func != nil {
frame := NewStacktraceFrame(fr.PC, fr.Function, fr.File, fr.Line, context, appPackagePrefixes)
if frame != nil {
frames = append(frames, frame)
}
}
if !more {
break
}
}
// If there are no frames, the entire stacktrace is nil
if len(frames) == 0 {
return nil
}
// Optimize the path where there's only 1 frame
if len(frames) == 1 {
return &Stacktrace{frames}
}
// Sentry wants the frames with the oldest first, so reverse them
for i, j := 0, len(frames)-1; i < j; i, j = i+1, j-1 {
frames[i], frames[j] = frames[j], frames[i]
}
return &Stacktrace{frames}
}
// Build a single frame using data returned from runtime.Caller.
//
// context is the number of surrounding lines that should be included for context.
// Setting context to 3 would try to get seven lines. Setting context to -1 returns
// one line with no surrounding context, and 0 returns no context.
//
// appPackagePrefixes is a list of prefixes used to check whether a package should
// be considered "in app".
func NewStacktraceFrame(pc uintptr, fName, file string, line, context int, appPackagePrefixes []string) *StacktraceFrame {
frame := &StacktraceFrame{AbsolutePath: file, Filename: trimPath(file), Lineno: line, InApp: false}
frame.Module, frame.Function = functionName(fName)
// `runtime.goexit` is effectively a placeholder that comes from
// runtime/asm_amd64.s and is meaningless.
if frame.Module == "runtime" && frame.Function == "goexit" {
return nil
}
if frame.Module == "main" {
frame.InApp = true
} else {
for _, prefix := range appPackagePrefixes {
if strings.HasPrefix(frame.Module, prefix) && !strings.Contains(frame.Module, "vendor") && !strings.Contains(frame.Module, "third_party") {
frame.InApp = true
}
}
}
if context > 0 {
contextLines, lineIdx := sourceCodeLoader.Load(file, line, context)
if len(contextLines) > 0 {
for i, line := range contextLines {
switch {
case i < lineIdx:
frame.PreContext = append(frame.PreContext, string(line))
case i == lineIdx:
frame.ContextLine = string(line)
default:
frame.PostContext = append(frame.PostContext, string(line))
}
}
}
} else if context == -1 {
contextLine, _ := sourceCodeLoader.Load(file, line, 0)
if len(contextLine) > 0 {
frame.ContextLine = string(contextLine[0])
}
}
return frame
}
// Retrieve the name of the package and function containing the PC.
func functionName(fName string) (pack string, name string) {
name = fName
// We get this:
// runtime/debug.*T·ptrmethod
// and want this:
// pack = runtime/debug
// name = *T.ptrmethod
if idx := strings.LastIndex(name, "."); idx != -1 {
pack = name[:idx]
name = name[idx+1:]
}
name = strings.Replace(name, "·", ".", -1)
return
}
type SourceCodeLoader interface {
Load(filename string, line, context int) ([][]byte, int)
}
var sourceCodeLoader SourceCodeLoader = &fsLoader{cache: make(map[string][][]byte)}
func SetSourceCodeLoader(loader SourceCodeLoader) {
sourceCodeLoader = loader
}
type fsLoader struct {
mu sync.Mutex
cache map[string][][]byte
}
func (fs *fsLoader) Load(filename string, line, context int) ([][]byte, int) {
fs.mu.Lock()
defer fs.mu.Unlock()
lines, ok := fs.cache[filename]
if !ok {
data, err := ioutil.ReadFile(filename)
if err != nil {
// cache errors as nil slice: code below handles it correctly
// otherwise when missing the source or running as a different user, we try
// reading the file on each error which is unnecessary
fs.cache[filename] = nil
return nil, 0
}
lines = bytes.Split(data, []byte{'\n'})
fs.cache[filename] = lines
}
if lines == nil {
// cached error from ReadFile: return no lines
return nil, 0
}
line-- // stack trace lines are 1-indexed
start := line - context
var idx int
if start < 0 {
start = 0
idx = line
} else {
idx = context
}
end := line + context + 1
if line >= len(lines) {
return nil, 0
}
if end > len(lines) {
end = len(lines)
}
return lines[start:end], idx
}
var trimPaths []string
// Try to trim the GOROOT or GOPATH prefix off of a filename
func trimPath(filename string) string {
for _, prefix := range trimPaths {
if trimmed := strings.TrimPrefix(filename, prefix); len(trimmed) < len(filename) {
return trimmed
}
}
return filename
}
func init() {
// Collect all source directories, and make sure they
// end in a trailing "separator"
for _, prefix := range build.Default.SrcDirs() {
if prefix[len(prefix)-1] != filepath.Separator {
prefix += string(filepath.Separator)
}
trimPaths = append(trimPaths, prefix)
}
}

View File

@ -1,20 +0,0 @@
package raven
type Writer struct {
Client *Client
Level Severity
Logger string // Logger name reported to Sentry
}
// Write formats the byte slice p into a string, and sends a message to
// Sentry at the severity level indicated by the Writer w.
func (w *Writer) Write(p []byte) (int, error) {
message := string(p)
packet := NewPacket(message, &Message{message, nil})
packet.Level = w.Level
packet.Logger = w.Logger
w.Client.Capture(packet, nil)
return len(p), nil
}

12
vendor/github.com/getsentry/sentry-go/.craft.yml generated vendored Normal file
View File

@ -0,0 +1,12 @@
github:
owner: getsentry
repo: sentry-go
preReleaseCommand: bash scripts/craft-pre-release.sh
changelogPolicy: simple
targets:
- name: github
tagPrefix: v
- name: registry
type: sdk
config:
canonical: "github:getsentry/sentry-go"

6
vendor/github.com/getsentry/sentry-go/.gitignore generated vendored Normal file
View File

@ -0,0 +1,6 @@
coverage.txt
# Just my personal way of tracking stuff — Kamil
FIXME.md
TODO.md
!NOTES.md

9
vendor/github.com/getsentry/sentry-go/.golangci.yml generated vendored Normal file
View File

@ -0,0 +1,9 @@
linters:
enable-all: true
disable:
- megacheck
- stylecheck
run:
skip-dirs:
- echo
- example/echo

29
vendor/github.com/getsentry/sentry-go/.travis.yml generated vendored Normal file
View File

@ -0,0 +1,29 @@
sudo: false
language: go
go:
- 1.10.x
- 1.11.x
- 1.12.x
env:
- GO111MODULE=on
before_install:
- curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.15.0
script:
- golangci-lint run
- go build
- go test
- go test -race
notifications:
webhooks:
urls:
- https://zeus.ci/hooks/befe9810-9285-11e9-b01a-0a580a281808/public/provider/travis/webhook
on_success: always
on_failure: always
on_start: always
on_cancel: always
on_error: always

104
vendor/github.com/getsentry/sentry-go/CHANGELOG.md generated vendored Normal file
View File

@ -0,0 +1,104 @@
# Changelog
## v0.2.1
- fix: Run `Contextify` integration on `Threads` as well
## v0.2.0
- feat: Add `SetTransaction()` method on the `Scope`
- feat: `fasthttp` framework support with `sentryfasthttp` package
- fix: Add `RWMutex` locks to internal `Hub` and `Scope` changes
## v0.1.3
- feat: Move frames context reading into `contextifyFramesIntegration` (#28)
_NOTE:_
In case of any performance isues due to source contexts IO, you can let us know and turn off the integration in the meantime with:
```go
sentry.Init(sentry.ClientOptions{
Integrations: func(integrations []sentry.Integration) []sentry.Integration {
var filteredIntegrations []sentry.Integration
for _, integration := range integrations {
if integration.Name() == "ContextifyFrames" {
continue
}
filteredIntegrations = append(filteredIntegrations, integration)
}
return filteredIntegrations
},
})
```
## v0.1.2
- feat: Better source code location resolution and more useful inapp frames (#26)
- feat: Use `noopTransport` when no `Dsn` provided (#27)
- ref: Allow empty `Dsn` instead of returning an error (#22)
- fix: Use `NewScope` instead of literal struct inside a `scope.Clear` call (#24)
- fix: Add to `WaitGroup` before the request is put inside a buffer (#25)
## v0.1.1
- fix: Check for initialized `Client` in `AddBreadcrumbs` (#20)
- build: Bump version when releasing with Craft (#19)
## v0.1.0
- First stable release! \o/
## v0.0.1-beta.5
- feat: **[breaking]** Add `NewHTTPTransport` and `NewHTTPSyncTransport` which accepts all transport options
- feat: New `HTTPSyncTransport` that blocks after each call
- feat: New `Echo` integration
- ref: **[breaking]** Remove `BufferSize` option from `ClientOptions` and move it to `HTTPTransport` instead
- ref: Export default `HTTPTransport`
- ref: Export `net/http` integration handler
- ref: Set `Request` instantly in the package handlers, not in `recoverWithSentry` so it can be accessed later on
- ci: Add craft config
## v0.0.1-beta.4
- feat: `IgnoreErrors` client option and corresponding integration
- ref: Reworked `net/http` integration, wrote better example and complete readme
- ref: Reworked `Gin` integration, wrote better example and complete readme
- ref: Reworked `Iris` integration, wrote better example and complete readme
- ref: Reworked `Negroni` integration, wrote better example and complete readme
- ref: Reworked `Martini` integration, wrote better example and complete readme
- ref: Remove `Handle()` from frameworks handlers and return it directly from New
## v0.0.1-beta.3
- feat: `Iris` framework support with `sentryiris` package
- feat: `Gin` framework support with `sentrygin` package
- feat: `Martini` framework support with `sentrymartini` package
- feat: `Negroni` framework support with `sentrynegroni` package
- feat: Add `Hub.Clone()` for easier frameworks integration
- feat: Return `EventID` from `Recovery` methods
- feat: Add `NewScope` and `NewEvent` functions and use them in the whole codebase
- feat: Add `AddEventProcessor` to the `Client`
- fix: Operate on requests body copy instead of the original
- ref: Try to read source files from the root directory, based on the filename as well, to make it work on AWS Lambda
- ref: Remove `gocertifi` dependence and document how to provide your own certificates
- ref: **[breaking]** Remove `Decorate` and `DecorateFunc` methods in favor of `sentryhttp` package
- ref: **[breaking]** Allow for integrations to live on the client, by passing client instance in `SetupOnce` method
- ref: **[breaking]** Remove `GetIntegration` from the `Hub`
- ref: **[breaking]** Remove `GlobalEventProcessors` getter from the public API
## v0.0.1-beta.2
- feat: Add `AttachStacktrace` client option to include stacktrace for messages
- feat: Add `BufferSize` client option to configure transport buffer size
- feat: Add `SetRequest` method on a `Scope` to control `Request` context data
- feat: Add `FromHTTPRequest` for `Request` type for easier extraction
- ref: Extract `Request` information more accurately
- fix: Attach `ServerName`, `Release`, `Dist`, `Environment` options to the event
- fix: Don't log events dropped due to full transport buffer as sent
- fix: Don't panic and create an appropriate event when called `CaptureException` or `Recover` with `nil` value
## v0.0.1-beta
- Initial release

41
vendor/github.com/getsentry/sentry-go/CONTRIBUTION.md generated vendored Normal file
View File

@ -0,0 +1,41 @@
## Testing
```bash
$ go test
```
### Watch mode
Use: https://github.com/cespare/reflex
```bash
$ reflex -g '*.go' -d "none" -- sh -c 'printf "\n"; go test'
```
### With data race detection
```bash
$ go test -race
```
### Coverage
```bash
$ go test -race -coverprofile=coverage.txt -covermode=atomic && go tool cover -html coverage.txt
```
## Linting
```bash
$ golangci-lint run
```
## Release
1. Update changelog with new version in `vX.X.X` format title and list of changes
2. Commit with `misc: vX.X.X changelog` commit message and push to `master`
3. Let `craft` do the rest
```bash
$ craft prepare X.X.X
$ craft publish X.X.X --skip-status-check
```

9
vendor/github.com/getsentry/sentry-go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,9 @@
Copyright (c) 2019 Sentry (https://sentry.io) and individual contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

392
vendor/github.com/getsentry/sentry-go/MIGRATION.md generated vendored Normal file
View File

@ -0,0 +1,392 @@
# `raven-go` to `sentry-go` Migration Guide
## Installation
raven-go
```go
go get github.com/getsentry/raven-go
```
sentry-go
```go
go get github.com/getsentry/sentry-go@v0.0.1
```
## Configuration
raven-go
```go
import "github.com/getsentry/raven-go"
func main() {
raven.SetDSN("https://16427b2f210046b585ee51fd8a1ac54f@sentry.io/1")
}
```
sentry-go
```go
import (
"fmt"
"github.com/getsentry/sentry-go"
)
func main() {
err := sentry.Init(sentry.ClientOptions{
Dsn: "https://16427b2f210046b585ee51fd8a1ac54f@sentry.io/1",
})
if err != nil {
fmt.Printf("Sentry initialization failed: %v\n", err)
}
}
```
raven-go
```go
SetDSN()
SetDefaultLoggerName()
SetDebug()
SetEnvironment()
SetRelease()
SetSampleRate()
SetIgnoreErrors()
SetIncludePaths()
```
sentry-go
```go
sentry.Init(sentry.ClientOptions{
Dsn: "https://16427b2f210046b585ee51fd8a1ac54f@sentry.io/1",
DebugWriter: os.Stderr,
Debug: true,
Environment: "environment",
Release: "release",
SampleRate: 0.5,
// IgnoreErrors: TBD,
// IncludePaths: TBD
})
```
Available options: see [Configuration](https://docs.sentry.io/platforms/go/config/) section.
### Providing SSL Certificates
By default, TLS uses the host's root CA set. If you don't have `ca-certificates` (which should be your go-to way of fixing the issue of missing ceritificates) and want to use `gocertifi` instead, you can provide pre-loaded cert files as one of the options to the `sentry.Init` call:
```go
package main
import (
"log"
"github.com/certifi/gocertifi"
"github.com/getsentry/sentry-go"
)
sentryClientOptions := sentry.ClientOptions{
Dsn: "https://16427b2f210046b585ee51fd8a1ac54f@sentry.io/1",
}
rootCAs, err := gocertifi.CACerts()
if err != nil {
log.Println("Coudnt load CA Certificates: %v\n", err)
} else {
sentryClientOptions.CaCerts = rootCAs
}
sentry.Init(sentryClientOptions)
```
## Usage
### Capturing Errors
raven-go
```go
f, err := os.Open("filename.ext")
if err != nil {
raven.CaptureError(err, nil)
}
```
sentry-go
```go
f, err := os.Open("filename.ext")
if err != nil {
sentry.CaptureException(err)
}
```
### Capturing Panics
raven-go
```go
raven.CapturePanic(func() {
// do all of the scary things here
}, nil)
```
sentry-go
```go
func() {
defer sentry.Recover()
// do all of the scary things here
}()
```
### Capturing Messages
raven-go
```go
raven.CaptureMessage("Something bad happened and I would like to know about that")
```
sentry-go
```go
sentry.CaptureMessage("Something bad happened and I would like to know about that")
```
### Capturing Events
raven-go
```go
packet := &raven.Packet{
Message: "Hand-crafted event",
Extra: &raven.Extra{
"runtime.Version": runtime.Version(),
"runtime.NumCPU": runtime.NumCPU(),
},
}
raven.Capture(packet)
```
sentry-go
```go
event := &sentry.NewEvent()
event.Message = "Hand-crafted event"
event.Extra["runtime.Version"] = runtime.Version()
event.Extra["runtime.NumCPU"] = runtime.NumCPU()
sentry.CaptureEvent(event)
```
### Additional Data
See Context section.
### Event Sampling
raven-go
```go
raven.SetSampleRate(0.25)
```
sentry-go
```go
sentry.Init(sentry.ClientOptions{
SampleRate: 0.25,
})
```
### Awaiting the response (not recommended)
```go
raven.CaptureMessageAndWait("Something bad happened and I would like to know about that")
```
sentry-go
```go
sentry.CaptureMessage("Something bad happened and I would like to know about that")
if sentry.Flush(time.Second * 2) {
// event delivered
} else {
// timeout reached
}
```
## Context
### Per-event
raven-go
```go
raven.CaptureError(err, map[string]string{"browser": "Firefox"}, &raven.Http{
Method: "GET",
URL: "https://example.com/raven-go"
})
```
sentry-go
```go
sentry.WithScope(func(scope *sentry.Scope) {
scope.SetTag("browser", "Firefox")
scope.SetContext("Request", map[string]string{
"Method": "GET",
"URL": "https://example.com/raven-go",
})
sentry.CaptureException(err)
})
```
### Globally
#### SetHttpContext
raven-go
```go
raven.SetHttpContext(&raven.Http{
Method: "GET",
URL: "https://example.com/raven-go",
})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetContext("Request", map[string]string{
"Method": "GET",
"URL": "https://example.com/raven-go",
})
})
```
#### SetTagsContext
raven-go
```go
t := map[string]string{"day": "Friday", "sport": "Weightlifting"}
raven.SetTagsContext(map[string]string{"day": "Friday", "sport": "Weightlifting"})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetTags(map[string]string{"day": "Friday", "sport": "Weightlifting"})
})
```
#### SetUserContext
raven-go
```go
raven.SetUserContext(&raven.User{
ID: "1337",
Username: "kamilogorek",
Email: "kamil@sentry.io",
IP: "127.0.0.1",
})
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.SetUser(sentry.User{
ID: "1337",
Username: "kamilogorek",
Email: "kamil@sentry.io",
IPAddress: "127.0.0.1",
})
})
```
#### ClearContext
raven-go
```go
raven.ClearContext()
```
sentry-go
```go
sentry.ConfigureScope(func(scope *sentry.Scope) {
scope.Clear()
})
```
#### WrapWithExtra
raven-go
```go
path := "filename.ext"
f, err := os.Open(path)
if err != nil {
err = raven.WrapWithExtra(err, map[string]string{"path": path, "cwd": os.Getwd()}
raven.CaptureError(err, nil)
}
```
sentry-go
```go
// use `sentry.WithScope`, see "Context / Per-event Section"
path := "filename.ext"
f, err := os.Open(path)
if err != nil {
sentry.WithScope(func(scope *sentry.Scope) {
sentry.SetExtras(map[string]interface{}{"path": path, "cwd": os.Getwd())
sentry.CaptureException(err)
})
}
```
## Integrations
### net/http
raven-go
```go
mux := http.NewServeMux
http.Handle("/", raven.Recoverer(mux))
// or
func root(w http.ResponseWriter, r *http.Request) {}
http.HandleFunc("/", raven.RecoveryHandler(root))
```
sentry-go
```go
sentryHandler := sentryhttp.New(sentryhttp.Options{
Repanic: false,
WaitForDelivery: true,
})
mux := http.NewServeMux
http.Handle("/", sentryHandler.Handle(mux))
// or
func root(w http.ResponseWriter, r *http.Request) {}
http.HandleFunc("/", sentryHandler.HandleFunc(root))
```

108
vendor/github.com/getsentry/sentry-go/README.md generated vendored Normal file
View File

@ -0,0 +1,108 @@
<p align="center">
<a href="https://sentry.io" target="_blank" align="center">
<img src="https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" width="280">
</a>
<br />
</p>
# Official Sentry SDK for Go
[![Build Status](https://travis-ci.com/getsentry/sentry-go.svg?branch=master)](https://travis-ci.com/getsentry/sentry-go)
[![Go Report Card](https://goreportcard.com/badge/github.com/getsentry/sentry-go)](https://goreportcard.com/report/github.com/getsentry/sentry-go)
`sentry-go` provides a Sentry client implementation for the Go programming language. This is the next line of the Go SDK for [Sentry](https://sentry.io/), intended to replace the `raven-go` package.
> Looking for the old `raven-go` SDK documentation? See the Legacy client section [here](https://docs.sentry.io/clients/go/).
> If you want to start using sentry-go instead, check out the [migration guide](https://docs.sentry.io/platforms/go/migration/).
## Requirements
We verify this package against N-2 recent versions of Go compiler. As of June 2019, those versions are:
* 1.10
* 1.11
* 1.12
## Installation
`sentry-go` can be installed like any other Go library through `go get`:
```bash
$ go get github.com/getsentry/sentry-go
```
Or, if you are already using Go Modules, specify a version number as well:
```bash
$ go get github.com/getsentry/sentry-go@v0.1.0
```
## Configuration
To use `sentry-go`, you’ll need to import the `sentry-go` package and initialize it with the client options that will include your DSN. If you specify the `SENTRY_DSN` environment variable, you can omit this value from options and it will be picked up automatically for you. The release and environment can also be specified in the environment variables `SENTRY_RELEASE` and `SENTRY_ENVIRONMENT` respectively.
More on this in [Configuration](https://docs.sentry.io/platforms/go/config/) section.
## Usage
By default, Sentry Go SDK uses asynchronous transport, which in the code example below requires an explicit awaiting for event delivery to be finished using `sentry.Flush` method. It is necessary, because otherwise the program would not wait for the async HTTP calls to return a response, and exit the process immediately when it reached the end of the `main` function. It would not be required inside a running goroutine or if you would use `HTTPSyncTransport`, which you can read about in `Transports` section.
```go
package main
import (
"fmt"
"os"
"time"
"github.com/getsentry/sentry-go"
)
func main() {
err := sentry.Init(sentry.ClientOptions{
Dsn: "___DSN___",
})
if err != nil {
fmt.Printf("Sentry initialization failed: %v\n", err)
}
f, err := os.Open("filename.ext")
if err != nil {
sentry.CaptureException(err)
sentry.Flush(time.Second * 5)
}
}
```
For more detailed information about how to get the most out of `sentry-go` there is additional documentation available:
- [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/context?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)
## Resources:
- [Bug Tracker](https://github.com/getsentry/sentry-go/issues)
- [GitHub Project](https://github.com/getsentry/sentry-go)
- [Godocs](https://godoc.org/github.com/getsentry/sentry-go)
- [@getsentry](https://twitter.com/getsentry) on Twitter for updates
## License
Licensed under the BSD license, see `LICENSE`
## Community
Want to join our Sentry's `community-golang` channel, get involved and help us improve the SDK?
Do not hesistate to shoot me up an email at [kamil@sentry.io](mailto:kamil@sentry.io) for Slack invite!

429
vendor/github.com/getsentry/sentry-go/client.go generated vendored Normal file
View File

@ -0,0 +1,429 @@
package sentry
import (
"context"
"crypto/x509"
"fmt"
"io"
"io/ioutil"
"log"
"math/rand"
"net/http"
"os"
"reflect"
"sort"
"time"
)
// Logger is an instance of log.Logger that is use to provide debug information about running Sentry Client
// can be enabled by either using `Logger.SetOutput` directly or with `Debug` client option
var Logger = log.New(ioutil.Discard, "[Sentry] ", log.LstdFlags) // nolint: gochecknoglobals
type EventProcessor func(event *Event, hint *EventHint) *Event
type EventModifier interface {
ApplyToEvent(event *Event, hint *EventHint) *Event
}
var globalEventProcessors []EventProcessor // nolint: gochecknoglobals
func AddGlobalEventProcessor(processor EventProcessor) {
globalEventProcessors = append(globalEventProcessors, processor)
}
// Integration allows for registering a functions that modify or discard captured events.
type Integration interface {
Name() string
SetupOnce(client *Client)
}
// ClientOptions that configures a SDK Client
type ClientOptions struct {
// The DSN to use. If the DSN is not set, the client is effectively disabled.
Dsn string
// In debug mode, the debug information is printed to stdout to help you understand what
// sentry is doing.
Debug bool
// 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).
SampleRate float32
// 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.
IgnoreErrors []string
// Before send callback.
BeforeSend func(event *Event, hint *EventHint) *Event
// Before breadcrumb add callback.
BeforeBreadcrumb func(breadcrumb *Breadcrumb, hint *BreadcrumbHint) *Breadcrumb
// Integrations to be installed on the current Client, receives default integrations
Integrations func([]Integration) []Integration
// io.Writer implementation that should be used with the `Debug` mode
DebugWriter io.Writer
// The transport to use.
// This is an instance of a struct implementing `Transport` interface.
// Defaults to `httpTransport` from `transport.go`
Transport Transport
// The server name to be reported.
ServerName string
// The release to be sent with events.
Release string
// The dist to be sent with events.
Dist string
// The environment to be sent with events.
Environment string
// Maximum number of breadcrumbs.
MaxBreadcrumbs int
// An optional pointer to `http.Transport` that will be used with a default HTTPTransport.
HTTPTransport *http.Transport
// An optional HTTP proxy to use.
// This will default to the `http_proxy` environment variable.
// or `https_proxy` if that one exists.
HTTPProxy string
// An optional HTTPS proxy to use.
// This will default to the `HTTPS_PROXY` environment variable
// or `http_proxy` if that one exists.
HTTPSProxy string
// An optionsl CaCerts to use.
// Defaults to `gocertifi.CACerts()`.
CaCerts *x509.CertPool
}
// Client is the underlying processor that's used by the main API and `Hub` instances.
type Client struct {
options ClientOptions
dsn *Dsn
eventProcessors []EventProcessor
integrations []Integration
Transport Transport
}
// NewClient creates and returns an instance of `Client` configured using `ClientOptions`.
func NewClient(options ClientOptions) (*Client, error) {
if options.Debug {
debugWriter := options.DebugWriter
if debugWriter == nil {
debugWriter = os.Stdout
}
Logger.SetOutput(debugWriter)
}
if options.Dsn == "" {
options.Dsn = os.Getenv("SENTRY_DSN")
}
if options.Release == "" {
options.Release = os.Getenv("SENTRY_RELEASE")
}
if options.Environment == "" {
options.Environment = os.Getenv("SENTRY_ENVIRONMENT")
}
var dsn *Dsn
if options.Dsn != "" {
var err error
dsn, err = NewDsn(options.Dsn)
if err != nil {
return nil, err
}
}
client := Client{
options: options,
dsn: dsn,
}
client.setupTransport()
client.setupIntegrations()
return &client, nil
}
func (client *Client) setupTransport() {
transport := client.options.Transport
if transport == nil {
if client.options.Dsn == "" {
transport = new(noopTransport)
} else {
transport = NewHTTPTransport()
}
}
transport.Configure(client.options)
client.Transport = transport
}
func (client *Client) setupIntegrations() {
integrations := []Integration{
new(contextifyFramesIntegration),
new(environmentIntegration),
new(modulesIntegration),
new(ignoreErrorsIntegration),
}
if client.options.Integrations != nil {
integrations = client.options.Integrations(integrations)
}
for _, integration := range integrations {
if client.integrationAlreadyInstalled(integration.Name()) {
Logger.Printf("Integration %s is already installed\n", integration.Name())
continue
}
client.integrations = append(client.integrations, integration)
integration.SetupOnce(client)
Logger.Printf("Integration installed: %s\n", integration.Name())
}
}
// AddEventProcessor adds an event processor to the client.
func (client *Client) AddEventProcessor(processor EventProcessor) {
client.eventProcessors = append(client.eventProcessors, processor)
}
// Options return `ClientOptions` for the current `Client`.
func (client Client) Options() ClientOptions {
return client.options
}
// CaptureMessage captures an arbitrary message.
func (client *Client) CaptureMessage(message string, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromMessage(message, LevelInfo)
return client.CaptureEvent(event, hint, scope)
}
// CaptureException captures an error.
func (client *Client) CaptureException(exception error, hint *EventHint, scope EventModifier) *EventID {
event := client.eventFromException(exception, LevelError)
return client.CaptureEvent(event, hint, scope)
}
// CaptureEvent captures an event on the currently active client if any.
//
// The event must already be assembled. Typically code would instead use
// the utility methods like `CaptureException`. The return value is the
// event ID. In case Sentry is disabled or event was dropped, the return value will be nil.
func (client *Client) CaptureEvent(event *Event, hint *EventHint, scope EventModifier) *EventID {
return client.processEvent(event, hint, scope)
}
// Recover captures a panic.
// Returns `EventID` if successfully, or `nil` if there's no error to recover from.
func (client *Client) Recover(err interface{}, hint *EventHint, scope EventModifier) *EventID {
if err == nil {
err = recover()
}
if err != nil {
if err, ok := err.(error); ok {
event := client.eventFromException(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
if err, ok := err.(string); ok {
event := client.eventFromMessage(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
}
return nil
}
// Recover captures a panic and passes relevant context object.
// Returns `EventID` if successfully, or `nil` if there's no error to recover from.
func (client *Client) RecoverWithContext(
ctx context.Context,
err interface{},
hint *EventHint,
scope EventModifier,
) *EventID {
if err == nil {
err = recover()
}
if err != nil {
if hint.Context == nil && ctx != nil {
hint.Context = ctx
}
if err, ok := err.(error); ok {
event := client.eventFromException(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
if err, ok := err.(string); ok {
event := client.eventFromMessage(err, LevelFatal)
return client.CaptureEvent(event, hint, scope)
}
}
return nil
}
// Flush notifies when all the buffered events have been sent by returning `true`
// or `false` if timeout was reached. It calls `Flush` method of the configured `Transport`.
func (client *Client) Flush(timeout time.Duration) bool {
return client.Transport.Flush(timeout)
}
func (client *Client) eventFromMessage(message string, level Level) *Event {
event := NewEvent()
event.Level = level
event.Message = message
if client.Options().AttachStacktrace {
event.Threads = []Thread{{
Stacktrace: NewStacktrace(),
Crashed: false,
Current: true,
}}
}
return event
}
func (client *Client) eventFromException(exception error, level Level) *Event {
if exception == nil {
event := NewEvent()
event.Level = level
event.Message = fmt.Sprintf("Called %s with nil value", callerFunctionName())
return event
}
stacktrace := ExtractStacktrace(exception)
if stacktrace == nil {
stacktrace = NewStacktrace()
}
event := NewEvent()
event.Level = level
event.Exception = []Exception{{
Value: exception.Error(),
Type: reflect.TypeOf(exception).String(),
Stacktrace: stacktrace,
}}
return event
}
func (client *Client) processEvent(event *Event, hint *EventHint, scope EventModifier) *EventID {
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 := rand.New(rand.NewSource(time.Now().UnixNano())).Float32()
if randomFloat > options.SampleRate {
Logger.Println("Event dropped due to SampleRate hit.")
return nil
}
}
if event = client.prepareEvent(event, hint, scope); event == nil {
return nil
}
if options.BeforeSend != nil {
h := &EventHint{}
if hint != nil {
h = hint
}
if event = options.BeforeSend(event, h); event == nil {
Logger.Println("Event dropped due to BeforeSend callback.")
return nil
}
}
client.Transport.SendEvent(event)
return &event.EventID
}
func (client *Client) prepareEvent(event *Event, hint *EventHint, scope EventModifier) *Event {
if event.EventID == "" {
event.EventID = EventID(uuid())
}
if event.Timestamp == 0 {
event.Timestamp = time.Now().Unix()
}
if event.Level == "" {
event.Level = LevelInfo
}
if event.ServerName == "" {
if client.Options().ServerName != "" {
event.ServerName = client.Options().ServerName
} else if hostname, err := os.Hostname(); err == nil {
event.ServerName = hostname
}
}
if event.Release == "" && client.Options().Release != "" {
event.Release = client.Options().Release
}
if event.Dist == "" && client.Options().Dist != "" {
event.Dist = client.Options().Dist
}
if event.Environment == "" && client.Options().Environment != "" {
event.Environment = client.Options().Environment
}
event.Platform = "go"
event.Sdk = SdkInfo{
Name: "sentry.go",
Version: Version,
Integrations: client.listIntegrations(),
Packages: []SdkPackage{{
Name: "sentry-go",
Version: Version,
}},
}
event = scope.ApplyToEvent(event, hint)
for _, processor := range client.eventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Client EventProcessors: %s\n", id)
return nil
}
}
for _, processor := range globalEventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Global EventProcessors: %s\n", id)
return nil
}
}
return event
}
func (client Client) listIntegrations() []string {
integrations := make([]string, 0, len(client.integrations))
for _, integration := range client.integrations {
integrations = append(integrations, integration.Name())
}
sort.Strings(integrations)
return integrations
}
func (client Client) integrationAlreadyInstalled(name string) bool {
for _, integration := range client.integrations {
if integration.Name() == name {
return true
}
}
return false
}

185
vendor/github.com/getsentry/sentry-go/dsn.go generated vendored Normal file
View File

@ -0,0 +1,185 @@
package sentry
import (
"encoding/json"
"fmt"
"net/url"
"strconv"
"strings"
"time"
)
type scheme string
const (
schemeHTTP scheme = "http"
schemeHTTPS scheme = "https"
)
func (scheme scheme) defaultPort() int {
switch scheme {
case schemeHTTPS:
return 443
case schemeHTTP:
return 80
default:
return 80
}
}
type DsnParseError struct {
Message string
}
func (e DsnParseError) Error() string {
return "[Sentry] DsnParseError: " + e.Message
}
// Dsn is used as the remote address source to client transport.
type Dsn struct {
scheme scheme
publicKey string
secretKey string
host string
port int
path string
projectID int
}
// NewDsn creates an instance od `Dsn` by parsing provided url in a `string` format.
// If Dsn is not set the client is effectively disabled.
func NewDsn(rawURL string) (*Dsn, error) {
// Parse
parsedURL, err := url.Parse(rawURL)
if err != nil {
return nil, &DsnParseError{"invalid url"}
}
// Scheme
var scheme scheme
switch parsedURL.Scheme {
case "http":
scheme = schemeHTTP
case "https":
scheme = schemeHTTPS
default:
return nil, &DsnParseError{"invalid scheme"}
}
// PublicKey
publicKey := parsedURL.User.Username()
if publicKey == "" {
return nil, &DsnParseError{"empty username"}
}
// SecretKey
var secretKey string
if parsedSecretKey, ok := parsedURL.User.Password(); ok {
secretKey = parsedSecretKey
}
// Host
host := parsedURL.Hostname()
if host == "" {
return nil, &DsnParseError{"empty host"}
}
// Port
var port int
if parsedURL.Port() != "" {
parsedPort, err := strconv.Atoi(parsedURL.Port())
if err != nil {
return nil, &DsnParseError{"invalid port"}
}
port = parsedPort
} else {
port = scheme.defaultPort()
}
// ProjectID
if len(parsedURL.Path) == 0 || parsedURL.Path == "/" {
return nil, &DsnParseError{"empty project id"}
}
pathSegments := strings.Split(parsedURL.Path[1:], "/")
projectID, err := strconv.Atoi(pathSegments[len(pathSegments)-1])
if err != nil {
return nil, &DsnParseError{"invalid project id"}
}
// Path
var path string
if len(pathSegments) > 1 {
path = "/" + strings.Join(pathSegments[0:len(pathSegments)-1], "/")
}
return &Dsn{
scheme: scheme,
publicKey: publicKey,
secretKey: secretKey,
host: host,
port: port,
path: path,
projectID: projectID,
}, nil
}
// String formats Dsn struct into a valid string url
func (dsn Dsn) String() string {
var url string
url += fmt.Sprintf("%s://%s", dsn.scheme, dsn.publicKey)
if dsn.secretKey != "" {
url += fmt.Sprintf(":%s", dsn.secretKey)
}
url += fmt.Sprintf("@%s", dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
url += fmt.Sprintf(":%d", dsn.port)
}
if dsn.path != "" {
url += dsn.path
}
url += fmt.Sprintf("/%d", dsn.projectID)
return url
}
// StoreAPIURL returns assembled url to be used in the transport.
// It points to configures Sentry instance.
func (dsn Dsn) StoreAPIURL() *url.URL {
var rawURL string
rawURL += fmt.Sprintf("%s://%s", dsn.scheme, dsn.host)
if dsn.port != dsn.scheme.defaultPort() {
rawURL += fmt.Sprintf(":%d", dsn.port)
}
rawURL += fmt.Sprintf("/api/%d/store/", dsn.projectID)
parsedURL, _ := url.Parse(rawURL)
return parsedURL
}
// RequestHeaders returns all the necessary headers that have to be used in the transport.
func (dsn Dsn) RequestHeaders() map[string]string {
auth := fmt.Sprintf("Sentry sentry_version=%d, sentry_timestamp=%d, "+
"sentry_client=sentry.go/%s, sentry_key=%s", 7, time.Now().Unix(), Version, dsn.publicKey)
if dsn.secretKey != "" {
auth = fmt.Sprintf("%s, sentry_secret=%s", auth, dsn.secretKey)
}
return map[string]string{
"Content-Type": "application/json",
"X-Sentry-Auth": auth,
}
}
func (dsn Dsn) MarshalJSON() ([]byte, error) {
return json.Marshal(dsn.String())
}
func (dsn *Dsn) UnmarshalJSON(data []byte) error {
var str string
_ = json.Unmarshal(data, &str)
newDsn, err := NewDsn(str)
if err != nil {
return err
}
*dsn = *newDsn
return nil
}

7
vendor/github.com/getsentry/sentry-go/go.mod generated vendored Normal file
View File

@ -0,0 +1,7 @@
module github.com/getsentry/sentry-go
require (
github.com/go-errors/errors v1.0.1
github.com/pingcap/errors v0.11.1
github.com/pkg/errors v0.8.1
)

6
vendor/github.com/getsentry/sentry-go/go.sum generated vendored Normal file
View File

@ -0,0 +1,6 @@
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/pingcap/errors v0.11.1 h1:BXFZ6MdDd2U1uJUa2sRAWTmm+nieEzuyYM0R4aUTcC8=
github.com/pingcap/errors v0.11.1/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=

319
vendor/github.com/getsentry/sentry-go/hub.go generated vendored Normal file
View File

@ -0,0 +1,319 @@
package sentry
import (
"context"
"sync"
"time"
)
type contextKey int
// HubContextKey is a context key used to store Hub on any context.Context type
const HubContextKey = contextKey(1)
// RequestContextKey is a context key used to store http.Request on the context passed to RecoverWithContext
const RequestContextKey = contextKey(2)
// Default maximum number of breadcrumbs added to an event. Can be overwritten `maxBreadcrumbs` option.
const defaultMaxBreadcrumbs = 30
// Absolute maximum number of breadcrumbs added to an event.
// The `maxBreadcrumbs` option cannot be higher than this value.
const maxBreadcrumbs = 100
// Initial instance of the Hub that has no `Client` bound and an empty `Scope`
var currentHub = NewHub(nil, NewScope()) // nolint: gochecknoglobals
// Hub is the central object that can manages scopes and clients.
//
// This can be used to capture events and manage the scope.
// The default hub that is available automatically.
//
// In most situations developers do not need to interface the hub. Instead
// toplevel convenience functions are exposed that will automatically dispatch
// to global (`CurrentHub`) hub. In some situations this might not be
// possible in which case it might become necessary to manually work with the
// hub. This is for instance the case when working with async code.
type Hub struct {
sync.RWMutex
stack *stack
lastEventID EventID
}
type layer struct {
client *Client
scope *Scope
}
type stack []*layer
// NewHub returns an instance of a `Hub` with provided `Client` and `Scope` bound.
func NewHub(client *Client, scope *Scope) *Hub {
hub := Hub{
stack: &stack{{
client: client,
scope: scope,
}},
}
return &hub
}
// CurrentHub returns an instance of previously initialized `Hub` stored in the global namespace.
func CurrentHub() *Hub {
return currentHub
}
// LastEventID returns an ID of last captured event for the current `Hub`.
func (hub *Hub) LastEventID() EventID {
return hub.lastEventID
}
func (hub *Hub) stackTop() *layer {
hub.RLock()
defer hub.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()
}
return NewHub(top.client, scope)
}
// 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
}
// Scope 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
}
// PushScope pushes a new scope for the current `Hub` and reuses previously bound `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 {
scope = top.scope.Clone()
} else {
scope = NewScope()
}
hub.Lock()
defer hub.Unlock()
*hub.stack = append(*hub.stack, &layer{
client: client,
scope: scope,
})
return scope
}
// PushScope pops the most recent scope for the current `Hub`.
func (hub *Hub) PopScope() {
hub.Lock()
defer hub.Unlock()
stack := *hub.stack
stackLen := len(stack)
if stackLen > 0 {
*hub.stack = stack[0 : stackLen-1]
}
}
// BindClient binds a new `Client` for the current `Hub`.
func (hub *Hub) BindClient(client *Client) {
top := hub.stackTop()
if top != nil {
top.client = client
}
}
// WithScope temporarily pushes a scope for a single call.
//
// A shorthand for:
// PushScope()
// f(scope)
// PopScope()
func (hub *Hub) WithScope(f func(scope *Scope)) {
scope := hub.PushScope()
defer hub.PopScope()
f(scope)
}
// ConfigureScope invokes a function that can modify the current scope.
//
// The function is passed a mutable reference to the `Scope` so that modifications
// can be performed.
func (hub *Hub) ConfigureScope(f func(scope *Scope)) {
scope := hub.Scope()
f(scope)
}
// CaptureEvent calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureEvent(event *Event) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.CaptureEvent(event, nil, scope)
}
// CaptureMessage calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureMessage(message string) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.CaptureMessage(message, nil, scope)
}
// CaptureException calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) CaptureException(exception error) *EventID {
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.CaptureException(exception, &EventHint{OriginalException: exception}, scope)
}
// AddBreadcrumb records a new breadcrumb.
//
// The total number of breadcrumbs that can be recorded are limited by the
// configuration on the client.
func (hub *Hub) AddBreadcrumb(breadcrumb *Breadcrumb, hint *BreadcrumbHint) {
client := hub.Client()
// If there's no client, just store it on the scope straight away
if client == nil {
hub.Scope().AddBreadcrumb(breadcrumb, maxBreadcrumbs)
return
}
options := client.Options()
max := defaultMaxBreadcrumbs
if options.MaxBreadcrumbs != 0 {
max = options.MaxBreadcrumbs
}
if max < 0 {
return
}
if options.BeforeBreadcrumb != nil {
h := &BreadcrumbHint{}
if hint != nil {
h = hint
}
if breadcrumb = options.BeforeBreadcrumb(breadcrumb, h); breadcrumb == nil {
Logger.Println("breadcrumb dropped due to BeforeBreadcrumb callback.")
return
}
}
if max > maxBreadcrumbs {
max = maxBreadcrumbs
}
hub.Scope().AddBreadcrumb(breadcrumb, max)
}
// Recover calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) Recover(err interface{}) *EventID {
if err == nil {
err = recover()
}
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.Recover(err, &EventHint{RecoveredException: err}, scope)
}
// RecoverWithContext calls the method of a same name on currently bound `Client` instance
// passing it a top-level `Scope`.
// Returns `EventID` if successfully, or `nil` if there's no `Scope` or `Client` available.
func (hub *Hub) RecoverWithContext(ctx context.Context, err interface{}) *EventID {
if err == nil {
err = recover()
}
client, scope := hub.Client(), hub.Scope()
if client == nil || scope == nil {
return nil
}
return client.RecoverWithContext(ctx, err, &EventHint{RecoveredException: err}, scope)
}
// Flush calls the method of a same name on currently bound `Client` instance.
func (hub *Hub) Flush(timeout time.Duration) bool {
client := hub.Client()
if client == nil {
return false
}
return client.Flush(timeout)
}
// HasHubOnContext checks whether `Hub` instance is bound to a given `Context` struct.
func HasHubOnContext(ctx context.Context) bool {
_, ok := ctx.Value(HubContextKey).(*Hub)
return ok
}
// GetHubFromContext tries to retrieve `Hub` instance from the given `Context` struct
// or return `nil` if one is not found.
func GetHubFromContext(ctx context.Context) *Hub {
if hub, ok := ctx.Value(HubContextKey).(*Hub); ok {
return hub
}
return nil
}
// 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)
}

376
vendor/github.com/getsentry/sentry-go/integrations.go generated vendored Normal file
View File

@ -0,0 +1,376 @@
package sentry
import (
"bufio"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"regexp"
"runtime"
"strings"
)
// ================================
// Modules Integration
// ================================
type modulesIntegration struct{}
var _modulesCache map[string]string // nolint: gochecknoglobals
func (mi *modulesIntegration) Name() string {
return "Modules"
}
func (mi *modulesIntegration) SetupOnce(client *Client) {
client.AddEventProcessor(mi.processor)
}
func (mi *modulesIntegration) processor(event *Event, hint *EventHint) *Event {
if event.Modules == nil {
event.Modules = extractModules()
}
return event
}
func extractModules() map[string]string {
if _modulesCache != nil {
return _modulesCache
}
extractedModules, err := getModules()
if err != nil {
Logger.Printf("ModuleIntegration wasn't able to extract modules: %v\n", err)
return nil
}
_modulesCache = extractedModules
return extractedModules
}
func getModules() (map[string]string, error) {
if fileExists("go.mod") {
return getModulesFromMod()
}
if fileExists("vendor") {
// Priority given to vendor created by modules
if fileExists("vendor/modules.txt") {
return getModulesFromVendorTxt()
}
if fileExists("vendor/vendor.json") {
return getModulesFromVendorJSON()
}
}
return nil, fmt.Errorf("module integration failed")
}
func getModulesFromMod() (map[string]string, error) {
modules := make(map[string]string)
file, err := os.Open("go.mod")
if err != nil {
return nil, fmt.Errorf("unable to open mod file")
}
defer file.Close()
areModulesPresent := false
scanner := bufio.NewScanner(file)
for scanner.Scan() {
splits := strings.Split(scanner.Text(), " ")
if splits[0] == "require" {
areModulesPresent = true
// Mod file has only 1 dependency
if len(splits) > 2 {
modules[strings.TrimSpace(splits[1])] = splits[2]
return modules, nil
}
} else if areModulesPresent && splits[0] != ")" {
modules[strings.TrimSpace(splits[0])] = splits[1]
}
}
if scannerErr := scanner.Err(); scannerErr != nil {
return nil, scannerErr
}
return modules, nil
}
func getModulesFromVendorTxt() (map[string]string, error) {
modules := make(map[string]string)
file, err := os.Open("vendor/modules.txt")
if err != nil {
return nil, fmt.Errorf("unable to open vendor/modules.txt")
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
splits := strings.Split(scanner.Text(), " ")
if splits[0] == "#" {
modules[splits[1]] = splits[2]
}
}
if scannerErr := scanner.Err(); scannerErr != nil {
return nil, scannerErr
}
return modules, nil
}
func getModulesFromVendorJSON() (map[string]string, error) {
modules := make(map[string]string)
file, err := ioutil.ReadFile("vendor/vendor.json")
if err != nil {
return nil, fmt.Errorf("unable to open vendor/vendor.json")
}
var vendor map[string]interface{}
if unmarshalErr := json.Unmarshal(file, &vendor); unmarshalErr != nil {
return nil, unmarshalErr
}
packages := vendor["package"].([]interface{})
// To avoid iterative dependencies, TODO: Change of default value
lastPath := "\n"
for _, value := range packages {
path := value.(map[string]interface{})["path"].(string)
if !strings.Contains(path, lastPath) {
// No versions are available through vendor.json
modules[path] = ""
lastPath = path
}
}
return modules, nil
}
// ================================
// Environment Integration
// ================================
type environmentIntegration struct{}
func (ei *environmentIntegration) Name() string {
return "Environment"
}
func (ei *environmentIntegration) SetupOnce(client *Client) {
client.AddEventProcessor(ei.processor)
}
func (ei *environmentIntegration) processor(event *Event, hint *EventHint) *Event {
if event.Contexts == nil {
event.Contexts = make(map[string]interface{})
}
event.Contexts["device"] = map[string]interface{}{
"arch": runtime.GOARCH,
"num_cpu": runtime.NumCPU(),
}
event.Contexts["os"] = map[string]interface{}{
"name": runtime.GOOS,
}
event.Contexts["runtime"] = map[string]interface{}{
"name": "go",
"version": runtime.Version(),
}
return event
}
// ================================
// Ignore Errors Integration
// ================================
type ignoreErrorsIntegration struct {
ignoreErrors []*regexp.Regexp
}
func (iei *ignoreErrorsIntegration) Name() string {
return "IgnoreErrors"
}
func (iei *ignoreErrorsIntegration) SetupOnce(client *Client) {
iei.ignoreErrors = transformStringsIntoRegexps(client.Options().IgnoreErrors)
client.AddEventProcessor(iei.processor)
}
func (iei *ignoreErrorsIntegration) processor(event *Event, hint *EventHint) *Event {
suspects := getIgnoreErrorsSuspects(event)
for _, suspect := range suspects {
for _, pattern := range iei.ignoreErrors {
if pattern.Match([]byte(suspect)) {
Logger.Printf("Event dropped due to being matched by `IgnoreErrors` option."+
"| Value matched: %s | Filter used: %s", suspect, pattern)
return nil
}
}
}
return event
}
func transformStringsIntoRegexps(strings []string) []*regexp.Regexp {
var exprs []*regexp.Regexp
for _, s := range strings {
r, err := regexp.Compile(s)
if err == nil {
exprs = append(exprs, r)
}
}
return exprs
}
func getIgnoreErrorsSuspects(event *Event) []string {
suspects := []string{}
if event.Message != "" {
suspects = append(suspects, event.Message)
}
for _, ex := range event.Exception {
suspects = append(suspects, ex.Type)
suspects = append(suspects, ex.Value)
}
return suspects
}
// ================================
// Contextify Frames Integration
// ================================
type contextifyFramesIntegration struct {
sr sourceReader
contextLines int
cachedLocations map[string]string
}
func (cfi *contextifyFramesIntegration) Name() string {
return "ContextifyFrames"
}
func (cfi *contextifyFramesIntegration) SetupOnce(client *Client) {
cfi.sr = newSourceReader()
cfi.contextLines = 5
cfi.cachedLocations = make(map[string]string)
client.AddEventProcessor(cfi.processor)
}
func (cfi *contextifyFramesIntegration) processor(event *Event, hint *EventHint) *Event {
// Range over all exceptions
for _, ex := range event.Exception {
// If it has no stacktrace, just bail out
if ex.Stacktrace == nil {
continue
}
// If it does, it should have frames, so try to contextify them
ex.Stacktrace.Frames = cfi.contextify(ex.Stacktrace.Frames)
}
// Range over all threads
for _, th := range event.Threads {
// If it has no stacktrace, just bail out
if th.Stacktrace == nil {
continue
}
// If it does, it should have frames, so try to contextify them
th.Stacktrace.Frames = cfi.contextify(th.Stacktrace.Frames)
}
return event
}
func (cfi *contextifyFramesIntegration) contextify(frames []Frame) []Frame {
contextifiedFrames := make([]Frame, 0, len(frames))
for _, frame := range frames {
if !frame.InApp {
contextifiedFrames = append(contextifiedFrames, frame)
continue
}
var path string
if cachedPath, ok := cfi.cachedLocations[frame.AbsPath]; ok {
path = cachedPath
} else {
// Optimize for happy path here
if fileExists(frame.AbsPath) {
path = frame.AbsPath
} else {
path = cfi.findNearbySourceCodeLocation(frame.AbsPath)
}
}
if path == "" {
contextifiedFrames = append(contextifiedFrames, frame)
continue
}
lines, contextLine := cfi.sr.readContextLines(path, frame.Lineno, cfi.contextLines)
contextifiedFrames = append(contextifiedFrames, cfi.addContextLinesToFrame(frame, lines, contextLine))
}
return contextifiedFrames
}
func (cfi *contextifyFramesIntegration) findNearbySourceCodeLocation(originalPath string) string {
trimmedPath := strings.TrimPrefix(originalPath, "/")
components := strings.Split(trimmedPath, "/")
for len(components) > 0 {
components = components[1:]
possibleLocation := strings.Join(components, "/")
if fileExists(possibleLocation) {
cfi.cachedLocations[originalPath] = possibleLocation
return possibleLocation
}
}
cfi.cachedLocations[originalPath] = ""
return ""
}
func (cfi *contextifyFramesIntegration) addContextLinesToFrame(frame Frame, lines [][]byte, contextLine int) Frame {
for i, line := range lines {
switch {
case i < contextLine:
frame.PreContext = append(frame.PreContext, string(line))
case i == contextLine:
frame.ContextLine = string(line)
default:
frame.PostContext = append(frame.PostContext, string(line))
}
}
return frame
}

180
vendor/github.com/getsentry/sentry-go/interfaces.go generated vendored Normal file
View File

@ -0,0 +1,180 @@
package sentry
import (
"context"
"fmt"
"io/ioutil"
"net"
"net/http"
"strings"
)
// Protocol Docs (kinda)
// https://github.com/getsentry/rust-sentry-types/blob/master/src/protocol/v7.rs
// Level marks the severity of the event
type Level string
const (
LevelDebug Level = "debug"
LevelInfo Level = "info"
LevelWarning Level = "warning"
LevelError Level = "error"
LevelFatal Level = "fatal"
)
// https://docs.sentry.io/development/sdk-dev/interfaces/sdk/
type SdkInfo struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
Integrations []string `json:"integrations,omitempty"`
Packages []SdkPackage `json:"packages,omitempty"`
}
type SdkPackage struct {
Name string `json:"name,omitempty"`
Version string `json:"version,omitempty"`
}
// TODO: This type could be more useful, as map of interface{} is too generic
// and requires a lot of type assertions in beforeBreadcrumb calls
// plus it could just be `map[string]interface{}` then
type BreadcrumbHint map[string]interface{}
// https://docs.sentry.io/development/sdk-dev/interfaces/breadcrumbs/
type Breadcrumb struct {
Category string `json:"category,omitempty"`
Data map[string]interface{} `json:"data,omitempty"`
Level Level `json:"level,omitempty"`
Message string `json:"message,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
Type string `json:"type,omitempty"`
}
// https://docs.sentry.io/development/sdk-dev/interfaces/user/
type User struct {
Email string `json:"email,omitempty"`
ID string `json:"id,omitempty"`
IPAddress string `json:"ip_address,omitempty"`
Username string `json:"username,omitempty"`
}
// https://docs.sentry.io/development/sdk-dev/interfaces/http/
type Request struct {
URL string `json:"url,omitempty"`
Method string `json:"method,omitempty"`
Data string `json:"data,omitempty"`
QueryString string `json:"query_string,omitempty"`
Cookies string `json:"cookies,omitempty"`
Headers map[string]string `json:"headers,omitempty"`
Env map[string]string `json:"env,omitempty"`
}
func (r Request) FromHTTPRequest(request *http.Request) Request {
// Method
r.Method = request.Method
// URL
protocol := schemeHTTP
if request.TLS != nil || request.Header.Get("X-Forwarded-Proto") == "https" {
protocol = schemeHTTPS
}
r.URL = fmt.Sprintf("%s://%s%s", protocol, request.Host, request.URL.Path)
// Headers
headers := make(map[string]string, len(request.Header))
for k, v := range request.Header {
headers[k] = strings.Join(v, ",")
}
headers["Host"] = request.Host
r.Headers = headers
// Cookies
r.Cookies = request.Header.Get("Cookie")
// Env
if addr, port, err := net.SplitHostPort(request.RemoteAddr); err == nil {
r.Env = map[string]string{"REMOTE_ADDR": addr, "REMOTE_PORT": port}
}
// QueryString
r.QueryString = request.URL.RawQuery
// Body
if request.GetBody != nil {
if bodyCopy, err := request.GetBody(); err == nil && bodyCopy != nil {
body, err := ioutil.ReadAll(bodyCopy)
if err == nil {
r.Data = string(body)
}
}
}
return r
}
// https://docs.sentry.io/development/sdk-dev/interfaces/exception/
type Exception struct {
Type string `json:"type,omitempty"`
Value string `json:"value,omitempty"`
Module string `json:"module,omitempty"`
Stacktrace *Stacktrace `json:"stacktrace,omitempty"`
RawStacktrace *Stacktrace `json:"raw_stacktrace,omitempty"`
}
type EventID string
// https://docs.sentry.io/development/sdk-dev/attributes/
type Event struct {
Breadcrumbs []*Breadcrumb `json:"breadcrumbs,omitempty"`
Contexts map[string]interface{} `json:"contexts,omitempty"`
Dist string `json:"dist,omitempty"`
Environment string `json:"environment,omitempty"`
EventID EventID `json:"event_id,omitempty"`
Extra map[string]interface{} `json:"extra,omitempty"`
Fingerprint []string `json:"fingerprint,omitempty"`
Level Level `json:"level,omitempty"`
Message string `json:"message,omitempty"`
Platform string `json:"platform,omitempty"`
Release string `json:"release,omitempty"`
Sdk SdkInfo `json:"sdk,omitempty"`
ServerName string `json:"server_name,omitempty"`
Threads []Thread `json:"threads,omitempty"`
Tags map[string]string `json:"tags,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"`
Transaction string `json:"transaction,omitempty"`
User User `json:"user,omitempty"`
Logger string `json:"logger,omitempty"`
Modules map[string]string `json:"modules,omitempty"`
Request Request `json:"request,omitempty"`
Exception []Exception `json:"exception,omitempty"`
}
func NewEvent() *Event {
event := Event{
Contexts: make(map[string]interface{}),
Extra: make(map[string]interface{}),
Tags: make(map[string]string),
Modules: make(map[string]string),
}
return &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"`
}
type EventHint struct {
Data interface{}
EventID string
OriginalException error
RecoveredException interface{}
Context context.Context
Request *http.Request
Response *http.Response
}

291
vendor/github.com/getsentry/sentry-go/scope.go generated vendored Normal file
View File

@ -0,0 +1,291 @@
package sentry
import (
"reflect"
"sync"
"time"
)
// Scope holds contextual data for the current scope.
//
// The scope is an object that can cloned efficiently and stores data that
// is locally relevant to an event. For instance the scope will hold recorded
// breadcrumbs and similar information.
//
// The scope can be interacted with in two ways:
//
// 1. the scope is routinely updated with information by functions such as
// `AddBreadcrumb` which will modify the currently top-most scope.
// 2. the topmost scope can also be configured through the `ConfigureScope`
// method.
//
// Note that the scope can only be modified but not inspected.
// Only the client can use the scope to extract information currently.
type Scope struct {
sync.RWMutex
breadcrumbs []*Breadcrumb
user User
tags map[string]string
contexts map[string]interface{}
extra map[string]interface{}
fingerprint []string
level Level
transaction string
request Request
eventProcessors []EventProcessor
}
func NewScope() *Scope {
scope := Scope{
breadcrumbs: make([]*Breadcrumb, 0),
tags: make(map[string]string),
contexts: make(map[string]interface{}),
extra: make(map[string]interface{}),
fingerprint: make([]string, 0),
}
return &scope
}
// AddBreadcrumb adds new breadcrumb to the current scope
// and optionaly throws the old one if limit is reached.
func (scope *Scope) AddBreadcrumb(breadcrumb *Breadcrumb, limit int) {
if breadcrumb.Timestamp == 0 {
breadcrumb.Timestamp = time.Now().Unix()
}
scope.Lock()
defer scope.Unlock()
breadcrumbs := append(scope.breadcrumbs, breadcrumb)
if len(breadcrumbs) > limit {
scope.breadcrumbs = breadcrumbs[1 : limit+1]
} else {
scope.breadcrumbs = breadcrumbs
}
}
// ClearBreadcrumbs clears all breadcrumbs from the current scope.
func (scope *Scope) ClearBreadcrumbs() {
scope.breadcrumbs = []*Breadcrumb{}
}
// SetUser sets new user for the current scope.
func (scope *Scope) SetUser(user User) {
scope.user = user
}
// SetRequest sets new user for the current scope.
func (scope *Scope) SetRequest(request Request) {
scope.request = request
}
// SetTag adds a tag to the current scope.
func (scope *Scope) SetTag(key, value string) {
scope.Lock()
defer scope.Unlock()
scope.tags[key] = value
}
// SetTags assigns multiple tags to the current scope.
func (scope *Scope) SetTags(tags map[string]string) {
scope.Lock()
defer scope.Unlock()
for k, v := range tags {
scope.tags[k] = v
}
}
// RemoveTag removes a tag from the current scope.
func (scope *Scope) RemoveTag(key string) {
scope.Lock()
defer scope.Unlock()
delete(scope.tags, key)
}
// SetContext adds a context to the current scope.
func (scope *Scope) SetContext(key string, value interface{}) {
scope.Lock()
defer scope.Unlock()
scope.contexts[key] = value
}
// SetContexts assigns multiple contexts to the current scope.
func (scope *Scope) SetContexts(contexts map[string]interface{}) {
scope.Lock()
defer scope.Unlock()
for k, v := range contexts {
scope.contexts[k] = v
}
}
// RemoveContext removes a context from the current scope.
func (scope *Scope) RemoveContext(key string) {
scope.Lock()
defer scope.Unlock()
delete(scope.contexts, key)
}
// SetExtra adds an extra to the current scope.
func (scope *Scope) SetExtra(key string, value interface{}) {
scope.Lock()
defer scope.Unlock()
scope.extra[key] = value
}
// SetExtras assigns multiple extras to the current scope.
func (scope *Scope) SetExtras(extra map[string]interface{}) {
scope.Lock()
defer scope.Unlock()
for k, v := range extra {
scope.extra[k] = v
}
}
// RemoveExtra removes a extra from the current scope.
func (scope *Scope) RemoveExtra(key string) {
scope.Lock()
defer scope.Unlock()
delete(scope.extra, key)
}
// SetFingerprint sets new fingerprint for the current scope.
func (scope *Scope) SetFingerprint(fingerprint []string) {
scope.fingerprint = fingerprint
}
// SetLevel sets new level for the current scope.
func (scope *Scope) SetLevel(level Level) {
scope.level = level
}
// SetTransaction sets new transaction name for the current transaction.
func (scope *Scope) SetTransaction(transactionName string) {
scope.transaction = transactionName
}
// Clone returns a copy of the current scope with all data copied over.
func (scope *Scope) Clone() *Scope {
scope.RLock()
defer scope.RUnlock()
clone := NewScope()
clone.user = scope.user
clone.breadcrumbs = make([]*Breadcrumb, len(scope.breadcrumbs))
copy(clone.breadcrumbs, scope.breadcrumbs)
for key, value := range scope.tags {
clone.tags[key] = value
}
for key, value := range scope.contexts {
clone.contexts[key] = value
}
for key, value := range scope.extra {
clone.extra[key] = value
}
clone.fingerprint = make([]string, len(scope.fingerprint))
copy(clone.fingerprint, scope.fingerprint)
clone.level = scope.level
clone.transaction = scope.transaction
clone.request = scope.request
return clone
}
// Clear removed the data from the current scope.
func (scope *Scope) Clear() {
*scope = *NewScope()
}
// AddEventProcessor adds an event processor to the current scope.
func (scope *Scope) AddEventProcessor(processor EventProcessor) {
scope.Lock()
defer scope.Unlock()
scope.eventProcessors = append(scope.eventProcessors, processor)
}
// ApplyToEvent takes the data from the current scope and attaches it to the event.
func (scope *Scope) ApplyToEvent(event *Event, hint *EventHint) *Event {
scope.RLock()
defer scope.RUnlock()
if len(scope.breadcrumbs) > 0 {
if event.Breadcrumbs == nil {
event.Breadcrumbs = []*Breadcrumb{}
}
event.Breadcrumbs = append(event.Breadcrumbs, scope.breadcrumbs...)
}
if len(scope.tags) > 0 {
if event.Tags == nil {
event.Tags = make(map[string]string)
}
for key, value := range scope.tags {
event.Tags[key] = value
}
}
if len(scope.contexts) > 0 {
if event.Contexts == nil {
event.Contexts = make(map[string]interface{})
}
for key, value := range scope.contexts {
event.Contexts[key] = value
}
}
if len(scope.extra) > 0 {
if event.Extra == nil {
event.Extra = make(map[string]interface{})
}
for key, value := range scope.extra {
event.Extra[key] = value
}
}
if (reflect.DeepEqual(event.User, User{})) {
event.User = scope.user
}
if (event.Fingerprint == nil || len(event.Fingerprint) == 0) &&
len(scope.fingerprint) > 0 {
event.Fingerprint = make([]string, len(scope.fingerprint))
copy(event.Fingerprint, scope.fingerprint)
}
if scope.level != "" {
event.Level = scope.level
}
if scope.transaction != "" {
event.Transaction = scope.transaction
}
if (reflect.DeepEqual(event.Request, Request{})) {
event.Request = scope.request
}
for _, processor := range scope.eventProcessors {
id := event.EventID
event = processor(event, hint)
if event == nil {
Logger.Printf("Event dropped by one of the Scope EventProcessors: %s\n", id)
return nil
}
}
return event
}

122
vendor/github.com/getsentry/sentry-go/sentry.go generated vendored Normal file
View File

@ -0,0 +1,122 @@
package sentry
import (
"context"
"time"
)
// Version Sentry-Go SDK Version
const Version = "0.2.1"
// Init initializes whole SDK by creating new `Client` and binding it to the current `Hub`
func Init(options ClientOptions) error {
hub := CurrentHub()
client, err := NewClient(options)
if err != nil {
return err
}
hub.BindClient(client)
return nil
}
// AddBreadcrumb records a new breadcrumb.
//
// The total number of breadcrumbs that can be recorded are limited by the
// configuration on the client.
func AddBreadcrumb(breadcrumb *Breadcrumb) {
hub := CurrentHub()
hub.AddBreadcrumb(breadcrumb, nil)
}
// CaptureMessage captures an arbitrary message.
func CaptureMessage(message string) *EventID {
hub := CurrentHub()
return hub.CaptureMessage(message)
}
// CaptureException captures an error.
func CaptureException(exception error) *EventID {
hub := CurrentHub()
return hub.CaptureException(exception)
}
// CaptureEvent captures an event on the currently active client if any.
//
// The event must already be assembled. Typically code would instead use
// the utility methods like `CaptureException`. The return value is the
// event ID. In case Sentry is disabled or event was dropped, the return value will be nil.
func CaptureEvent(event *Event) *EventID {
hub := CurrentHub()
return hub.CaptureEvent(event)
}
// Recover captures a panic.
func Recover() *EventID {
if err := recover(); err != nil {
hub := CurrentHub()
return hub.Recover(err)
}
return nil
}
// Recover captures a panic and passes relevant context object.
func RecoverWithContext(ctx context.Context) *EventID {
if err := recover(); err != nil {
var hub *Hub
if HasHubOnContext(ctx) {
hub = GetHubFromContext(ctx)
} else {
hub = CurrentHub()
}
return hub.RecoverWithContext(ctx, err)
}
return nil
}
// WithScope temporarily pushes a scope for a single call.
//
// This function takes one argument, a callback that executes
// in the context of that scope.
//
// This is useful when extra data should be send with a single capture call
// for instance a different level or tags
func WithScope(f func(scope *Scope)) {
hub := CurrentHub()
hub.WithScope(f)
}
// ConfigureScope invokes a function that can modify the current scope.
//
// The function is passed a mutable reference to the `Scope` so that modifications
// can be performed.
func ConfigureScope(f func(scope *Scope)) {
hub := CurrentHub()
hub.ConfigureScope(f)
}
// PushScope pushes a new scope.
func PushScope() {
hub := CurrentHub()
hub.PushScope()
}
// PopScope pushes a new scope.
func PopScope() {
hub := CurrentHub()
hub.PopScope()
}
// Flush notifies when all the buffered events have been sent by returning `true`
// or `false` if timeout was reached.
func Flush(timeout time.Duration) bool {
hub := CurrentHub()
return hub.Flush(timeout)
}
// LastEventID returns an ID of last captured event.
func LastEventID() EventID {
hub := CurrentHub()
return hub.LastEventID()
}

69
vendor/github.com/getsentry/sentry-go/sourcereader.go generated vendored Normal file
View File

@ -0,0 +1,69 @@
package sentry
import (
"bytes"
"io/ioutil"
"sync"
)
type sourceReader struct {
mu sync.Mutex
cache map[string][][]byte
}
func newSourceReader() sourceReader {
return sourceReader{
cache: make(map[string][][]byte),
}
}
func (sr *sourceReader) readContextLines(filename string, line, context int) ([][]byte, int) {
sr.mu.Lock()
defer sr.mu.Unlock()
lines, ok := sr.cache[filename]
if !ok {
data, err := ioutil.ReadFile(filename)
if err != nil {
sr.cache[filename] = nil
return nil, 0
}
lines = bytes.Split(data, []byte{'\n'})
sr.cache[filename] = lines
}
return sr.calculateContextLines(lines, line, context)
}
// `contextLine` points to a line that caused an issue itself, in relation to returned slice
func (sr *sourceReader) calculateContextLines(lines [][]byte, line, context int) ([][]byte, int) {
// Stacktrace lines are 1-indexed, slices are 0-indexed
line--
contextLine := context
if lines == nil || line >= len(lines) || line < 0 {
return nil, 0
}
if context < 0 {
context = 0
contextLine = 0
}
start := line - context
if start < 0 {
contextLine += start
start = 0
}
end := line + context + 1
if end > len(lines) {
end = len(lines)
}
return lines[start:end], contextLine
}

257
vendor/github.com/getsentry/sentry-go/stacktrace.go generated vendored Normal file
View File

@ -0,0 +1,257 @@
package sentry
import (
"go/build"
"path/filepath"
"reflect"
"regexp"
"runtime"
"strings"
)
const unknown string = "unknown"
// The module download is split into two parts: downloading the go.mod and downloading the actual code.
// If you have dependencies only needed for tests, then they will show up in your go.mod,
// and go get will download their go.mods, but it will not download their code.
// The test-only dependencies get downloaded only when you need it, such as the first time you run go test.
//
// https://github.com/golang/go/issues/26913#issuecomment-411976222
// Stacktrace holds information about the frames of the stack.
type Stacktrace struct {
Frames []Frame `json:"frames,omitempty"`
FramesOmitted []uint `json:"frames_omitted,omitempty"`
}
// NewStacktrace creates a stacktrace using `runtime.Callers`.
func NewStacktrace() *Stacktrace {
pcs := make([]uintptr, 100)
n := runtime.Callers(1, pcs)
if n == 0 {
return nil
}
frames := extractFrames(pcs[:n])
frames = filterFrames(frames)
stacktrace := Stacktrace{
Frames: frames,
}
return &stacktrace
}
// ExtractStacktrace creates a new `Stacktrace` based on the given `error` object.
// TODO: Make it configurable so that anyone can provide their own implementation?
// Use of reflection allows us to not have a hard dependency on any given package, so we don't have to import it
func ExtractStacktrace(err error) *Stacktrace {
method := extractReflectedStacktraceMethod(err)
if !method.IsValid() {
return nil
}
pcs := extractPcs(method)
if len(pcs) == 0 {
return nil
}
frames := extractFrames(pcs)
frames = filterFrames(frames)
stacktrace := Stacktrace{
Frames: frames,
}
return &stacktrace
}
func extractReflectedStacktraceMethod(err error) reflect.Value {
var method reflect.Value
// https://github.com/pingcap/errors
methodGetStackTracer := reflect.ValueOf(err).MethodByName("GetStackTracer")
// https://github.com/pkg/errors
methodStackTrace := reflect.ValueOf(err).MethodByName("StackTrace")
// https://github.com/go-errors/errors
methodStackFrames := reflect.ValueOf(err).MethodByName("StackFrames")
if methodGetStackTracer.IsValid() {
stacktracer := methodGetStackTracer.Call(make([]reflect.Value, 0))[0]
stacktracerStackTrace := reflect.ValueOf(stacktracer).MethodByName("StackTrace")
if stacktracerStackTrace.IsValid() {
method = stacktracerStackTrace
}
}
if methodStackTrace.IsValid() {
method = methodStackTrace
}
if methodStackFrames.IsValid() {
method = methodStackFrames
}
return method
}
func extractPcs(method reflect.Value) []uintptr {
var pcs []uintptr
stacktrace := method.Call(make([]reflect.Value, 0))[0]
if stacktrace.Kind() != reflect.Slice {
return nil
}
for i := 0; i < stacktrace.Len(); i++ {
pc := stacktrace.Index(i)
if pc.Kind() == reflect.Uintptr {
pcs = append(pcs, uintptr(pc.Uint()))
continue
}
if pc.Kind() == reflect.Struct {
field := pc.FieldByName("ProgramCounter")
if field.IsValid() && field.Kind() == reflect.Uintptr {
pcs = append(pcs, uintptr(field.Uint()))
continue
}
}
}
return pcs
}
// https://docs.sentry.io/development/sdk-dev/interfaces/stacktrace/
type Frame struct {
Function string `json:"function,omitempty"`
Symbol string `json:"symbol,omitempty"`
Module string `json:"module,omitempty"`
Package string `json:"package,omitempty"`
Filename string `json:"filename,omitempty"`
AbsPath string `json:"abs_path,omitempty"`
Lineno int `json:"lineno,omitempty"`
Colno int `json:"colno,omitempty"`
PreContext []string `json:"pre_context,omitempty"`
ContextLine string `json:"context_line,omitempty"`
PostContext []string `json:"post_context,omitempty"`
InApp bool `json:"in_app,omitempty"`
Vars map[string]interface{} `json:"vars,omitempty"`
}
// NewFrame assembles a stacktrace frame out of `runtime.Frame`.
func NewFrame(f runtime.Frame) Frame {
abspath := f.File
filename := f.File
function := f.Function
var module string
if filename != "" {
filename = extractFilename(filename)
} else {
filename = unknown
}
if abspath == "" {
abspath = unknown
}
if function != "" {
module, function = deconstructFunctionName(function)
}
frame := Frame{
AbsPath: abspath,
Filename: filename,
Lineno: f.Line,
Module: module,
Function: function,
}
frame.InApp = isInAppFrame(frame)
return frame
}
func extractFrames(pcs []uintptr) []Frame {
var frames []Frame
callersFrames := runtime.CallersFrames(pcs)
for {
callerFrame, more := callersFrames.Next()
frames = append([]Frame{
NewFrame(callerFrame),
}, frames...)
if !more {
break
}
}
return frames
}
func filterFrames(frames []Frame) []Frame {
isTestFileRegexp := regexp.MustCompile(`getsentry/sentry-go/.+_test.go`)
isExampleFileRegexp := regexp.MustCompile(`getsentry/sentry-go/example/`)
filteredFrames := make([]Frame, 0, len(frames))
for _, frame := range frames {
// go runtime frames
if frame.Module == "runtime" || frame.Module == "testing" {
continue
}
// sentry internal frames
isTestFile := isTestFileRegexp.MatchString(frame.AbsPath)
isExampleFile := isExampleFileRegexp.MatchString(frame.AbsPath)
if strings.Contains(frame.AbsPath, "github.com/getsentry/sentry-go") &&
!isTestFile &&
!isExampleFile {
continue
}
filteredFrames = append(filteredFrames, frame)
}
return filteredFrames
}
func extractFilename(path string) string {
_, file := filepath.Split(path)
return file
}
func isInAppFrame(frame Frame) bool {
if strings.HasPrefix(frame.AbsPath, build.Default.GOROOT) ||
strings.Contains(frame.Module, "vendor") ||
strings.Contains(frame.Module, "third_party") {
return false
}
return true
}
// Transform `runtime/debug.*T·ptrmethod` into `{ module: runtime/debug, function: *T.ptrmethod }`
func deconstructFunctionName(name string) (module string, function string) {
if idx := strings.LastIndex(name, "."); idx != -1 {
module = name[:idx]
function = name[idx+1:]
}
function = strings.Replace(function, "·", ".", -1)
return module, function
}
func callerFunctionName() string {
pcs := make([]uintptr, 1)
runtime.Callers(3, pcs)
callersFrames := runtime.CallersFrames(pcs)
callerFrame, _ := callersFrames.Next()
_, function := deconstructFunctionName(callerFrame.Function)
return function
}

316
vendor/github.com/getsentry/sentry-go/transport.go generated vendored Normal file
View File

@ -0,0 +1,316 @@
package sentry
import (
"bytes"
"crypto/tls"
"encoding/json"
"net/http"
"net/url"
"strconv"
"sync"
"time"
)
const defaultBufferSize = 30
const defaultRetryAfter = time.Second * 60
const defaultTimeout = time.Second * 30
// Transport is used by the `Client` to deliver events to remote server.
type Transport interface {
Flush(timeout time.Duration) bool
Configure(options ClientOptions)
SendEvent(event *Event)
}
func getProxyConfig(options ClientOptions) func(*http.Request) (*url.URL, error) {
if options.HTTPSProxy != "" {
return func(_ *http.Request) (*url.URL, error) {
return url.Parse(options.HTTPSProxy)
}
} else if options.HTTPProxy != "" {
return func(_ *http.Request) (*url.URL, error) {
return url.Parse(options.HTTPProxy)
}
}
return http.ProxyFromEnvironment
}
func getTLSConfig(options ClientOptions) *tls.Config {
if options.CaCerts != nil {
return &tls.Config{
RootCAs: options.CaCerts,
}
}
return nil
}
func retryAfter(now time.Time, r *http.Response) time.Duration {
retryAfterHeader := r.Header["Retry-After"]
if retryAfterHeader == nil {
return defaultRetryAfter
}
if date, err := time.Parse(time.RFC1123, retryAfterHeader[0]); err == nil {
return date.Sub(now)
}
if seconds, err := strconv.Atoi(retryAfterHeader[0]); err == nil {
return time.Second * time.Duration(seconds)
}
return defaultRetryAfter
}
// ================================
// HTTPTransport
// ================================
// HTTPTransport is a default implementation of `Transport` interface used by `Client`.
type HTTPTransport struct {
dsn *Dsn
client *http.Client
transport *http.Transport
buffer chan *http.Request
disabledUntil time.Time
wg sync.WaitGroup
start sync.Once
// Size of the transport buffer. Defaults to 30.
BufferSize int
// HTTP Client request timeout. Defaults to 30 seconds.
Timeout time.Duration
}
// NewHTTPTransport returns a new pre-configured instance of HTTPTransport
func NewHTTPTransport() *HTTPTransport {
transport := HTTPTransport{
BufferSize: defaultBufferSize,
Timeout: defaultTimeout,
}
return &transport
}
// Configure is called by the `Client` itself, providing it it's own `ClientOptions`.
func (t *HTTPTransport) Configure(options ClientOptions) {
dsn, err := NewDsn(options.Dsn)
if err != nil {
Logger.Printf("%v\n", err)
return
}
t.dsn = dsn
t.buffer = make(chan *http.Request, t.BufferSize)
if options.HTTPTransport != nil {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
}
t.client = &http.Client{
Transport: t.transport,
Timeout: t.Timeout,
}
t.start.Do(func() {
go t.worker()
})
}
// SendEvent assembles a new packet out of `Event` and sends it to remote server.
func (t *HTTPTransport) SendEvent(event *Event) {
if t.dsn == nil || time.Now().Before(t.disabledUntil) {
return
}
body, _ := json.Marshal(event)
request, _ := http.NewRequest(
http.MethodPost,
t.dsn.StoreAPIURL().String(),
bytes.NewBuffer(body),
)
for headerKey, headerValue := range t.dsn.RequestHeaders() {
request.Header.Set(headerKey, headerValue)
}
t.wg.Add(1)
select {
case t.buffer <- request:
Logger.Printf(
"Sending %s event [%s] to %s project: %d\n",
event.Level,
event.EventID,
t.dsn.host,
t.dsn.projectID,
)
default:
t.wg.Done()
Logger.Println("Event dropped due to transport buffer being full.")
// worker would block, drop the packet
}
}
// Flush notifies when all the buffered events have been sent by returning `true`
// or `false` if timeout was reached.
func (t *HTTPTransport) Flush(timeout time.Duration) bool {
c := make(chan struct{})
go func() {
t.wg.Wait()
close(c)
}()
select {
case <-c:
Logger.Println("Buffer flushed successfully.")
return true
case <-time.After(timeout):
Logger.Println("Buffer flushing reached the timeout.")
return false
}
}
func (t *HTTPTransport) worker() {
for request := range t.buffer {
if time.Now().Before(t.disabledUntil) {
t.wg.Done()
continue
}
response, err := t.client.Do(request)
if err != nil {
Logger.Printf("There was an issue with sending an event: %v", err)
}
if response != nil && response.StatusCode == http.StatusTooManyRequests {
t.disabledUntil = time.Now().Add(retryAfter(time.Now(), response))
Logger.Printf("Too many requests, backing off till: %s\n", t.disabledUntil)
}
t.wg.Done()
}
}
// ================================
// HTTPSyncTransport
// ================================
// HTTPSyncTransport is an implementation of `Transport` interface which blocks after each captured event.
type HTTPSyncTransport struct {
dsn *Dsn
client *http.Client
transport *http.Transport
disabledUntil time.Time
// HTTP Client request timeout. Defaults to 30 seconds.
Timeout time.Duration
}
// NewHTTPSyncTransport returns a new pre-configured instance of HTTPSyncTransport
func NewHTTPSyncTransport() *HTTPSyncTransport {
transport := HTTPSyncTransport{
Timeout: defaultTimeout,
}
return &transport
}
// Configure is called by the `Client` itself, providing it it's own `ClientOptions`.
func (t *HTTPSyncTransport) Configure(options ClientOptions) {
dsn, err := NewDsn(options.Dsn)
if err != nil {
Logger.Printf("%v\n", err)
return
}
t.dsn = dsn
if options.HTTPTransport != nil {
t.transport = options.HTTPTransport
} else {
t.transport = &http.Transport{
Proxy: getProxyConfig(options),
TLSClientConfig: getTLSConfig(options),
}
}
t.client = &http.Client{
Transport: t.transport,
Timeout: t.Timeout,
}
}
// SendEvent assembles a new packet out of `Event` and sends it to remote server.
func (t *HTTPSyncTransport) SendEvent(event *Event) {
if t.dsn == nil || time.Now().Before(t.disabledUntil) {
return
}
body, _ := json.Marshal(event)
request, _ := http.NewRequest(
http.MethodPost,
t.dsn.StoreAPIURL().String(),
bytes.NewBuffer(body),
)
for headerKey, headerValue := range t.dsn.RequestHeaders() {
request.Header.Set(headerKey, headerValue)
}
Logger.Printf(
"Sending %s event [%s] to %s project: %d\n",
event.Level,
event.EventID,
t.dsn.host,
t.dsn.projectID,
)
response, err := t.client.Do(request)
if err != nil {
Logger.Printf("There was an issue with sending an event: %v", err)
}
if response != nil && response.StatusCode == http.StatusTooManyRequests {
t.disabledUntil = time.Now().Add(retryAfter(time.Now(), response))
Logger.Printf("Too many requests, backing off till: %s\n", t.disabledUntil)
}
}
// Flush notifies when all the buffered events have been sent by returning `true`
// or `false` if timeout was reached. No-op for HTTPSyncTransport.
func (t *HTTPSyncTransport) Flush(_ time.Duration) bool {
return true
}
// ================================
// noopTransport
// ================================
// noopTransport is an implementation of `Transport` interface which drops all the events.
// Only used internally when an empty DSN is provided, which effectively disables the SDK.
type noopTransport struct{}
func (t *noopTransport) Configure(options ClientOptions) {
Logger.Println("Sentry client initialized with an empty DSN. Using noopTransport. No events will be delivered.")
}
func (t *noopTransport) SendEvent(event *Event) {
Logger.Println("Event dropped due to noopTransport usage.")
}
func (t *noopTransport) Flush(_ time.Duration) bool {
return true
}

34
vendor/github.com/getsentry/sentry-go/util.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
package sentry
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"os"
)
func uuid() string {
id := make([]byte, 16)
_, _ = io.ReadFull(rand.Reader, id)
id[6] &= 0x0F // clear version
id[6] |= 0x40 // set version to 4 (random uuid)
id[8] &= 0x3F // clear variant
id[8] |= 0x80 // set to IETF variant
return hex.EncodeToString(id)
}
func fileExists(fileName string) bool {
if _, err := os.Stat(fileName); err != nil {
return false
}
return true
}
// nolint: deadcode, unused
func prettyPrint(data interface{}) {
dbg, _ := json.MarshalIndent(data, "", " ")
fmt.Println(string(dbg))
}

View File

@ -1,24 +0,0 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so
# Folders
_obj
_test
# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out
*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*
_testmain.go
*.exe
*.test
*.prof

View File

@ -1,15 +0,0 @@
language: go
go_import_path: github.com/pkg/errors
go:
- 1.4.x
- 1.5.x
- 1.6.x
- 1.7.x
- 1.8.x
- 1.9.x
- 1.10.x
- 1.11.x
- tip
script:
- go test -v ./...

23
vendor/github.com/pkg/errors/LICENSE generated vendored
View File

@ -1,23 +0,0 @@
Copyright (c) 2015, Dave Cheney <dave@cheney.net>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,52 +0,0 @@
# errors [![Travis-CI](https://travis-ci.org/pkg/errors.svg)](https://travis-ci.org/pkg/errors) [![AppVeyor](https://ci.appveyor.com/api/projects/status/b98mptawhudj53ep/branch/master?svg=true)](https://ci.appveyor.com/project/davecheney/errors/branch/master) [![GoDoc](https://godoc.org/github.com/pkg/errors?status.svg)](http://godoc.org/github.com/pkg/errors) [![Report card](https://goreportcard.com/badge/github.com/pkg/errors)](https://goreportcard.com/report/github.com/pkg/errors) [![Sourcegraph](https://sourcegraph.com/github.com/pkg/errors/-/badge.svg)](https://sourcegraph.com/github.com/pkg/errors?badge)
Package errors provides simple error handling primitives.
`go get github.com/pkg/errors`
The traditional error handling idiom in Go is roughly akin to
```go
if err != nil {
return err
}
```
which applied recursively up the call stack results in error reports without context or debugging information. The errors package allows programmers to add context to the failure path in their code in a way that does not destroy the original value of the error.
## Adding context to an error
The errors.Wrap function returns a new error that adds context to the original error. For example
```go
_, err := ioutil.ReadAll(r)
if err != nil {
return errors.Wrap(err, "read failed")
}
```
## Retrieving the cause of an error
Using `errors.Wrap` constructs a stack of errors, adding context to the preceding error. Depending on the nature of the error it may be necessary to reverse the operation of errors.Wrap to retrieve the original error for inspection. Any error value which implements this interface can be inspected by `errors.Cause`.
```go
type causer interface {
Cause() error
}
```
`errors.Cause` will recursively retrieve the topmost error which does not implement `causer`, which is assumed to be the original cause. For example:
```go
switch err := errors.Cause(err).(type) {
case *MyError:
// handle specifically
default:
// unknown error
}
```
[Read the package documentation for more information](https://godoc.org/github.com/pkg/errors).
## Contributing
We welcome pull requests, bug fixes and issue reports. With that said, the bar for adding new symbols to this package is intentionally set high.
Before proposing a change, please discuss your change by raising an issue.
## License
BSD-2-Clause

View File

@ -1,32 +0,0 @@
version: build-{build}.{branch}
clone_folder: C:\gopath\src\github.com\pkg\errors
shallow_clone: true # for startup speed
environment:
GOPATH: C:\gopath
platform:
- x64
# http://www.appveyor.com/docs/installed-software
install:
# some helpful output for debugging builds
- go version
- go env
# pre-installed MinGW at C:\MinGW is 32bit only
# but MSYS2 at C:\msys64 has mingw64
- set PATH=C:\msys64\mingw64\bin;%PATH%
- gcc --version
- g++ --version
build_script:
- go install -v ./...
test_script:
- set PATH=C:\gopath\bin;%PATH%
- go test -v ./...
#artifacts:
# - path: '%GOPATH%\bin\*.exe'
deploy: off

View File

@ -1,282 +0,0 @@
// Package errors provides simple error handling primitives.
//
// The traditional error handling idiom in Go is roughly akin to
//
// if err != nil {
// return err
// }
//
// which when applied recursively up the call stack results in error reports
// without context or debugging information. The errors package allows
// programmers to add context to the failure path in their code in a way
// that does not destroy the original value of the error.
//
// Adding context to an error
//
// The errors.Wrap function returns a new error that adds context to the
// original error by recording a stack trace at the point Wrap is called,
// together with the supplied message. For example
//
// _, err := ioutil.ReadAll(r)
// if err != nil {
// return errors.Wrap(err, "read failed")
// }
//
// If additional control is required, the errors.WithStack and
// errors.WithMessage functions destructure errors.Wrap into its component
// operations: annotating an error with a stack trace and with a message,
// respectively.
//
// Retrieving the cause of an error
//
// Using errors.Wrap constructs a stack of errors, adding context to the
// preceding error. Depending on the nature of the error it may be necessary
// to reverse the operation of errors.Wrap to retrieve the original error
// for inspection. Any error value which implements this interface
//
// type causer interface {
// Cause() error
// }
//
// can be inspected by errors.Cause. errors.Cause will recursively retrieve
// the topmost error that does not implement causer, which is assumed to be
// the original cause. For example:
//
// switch err := errors.Cause(err).(type) {
// case *MyError:
// // handle specifically
// default:
// // unknown error
// }
//
// Although the causer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// Formatted printing of errors
//
// All error values returned from this package implement fmt.Formatter and can
// be formatted by the fmt package. The following verbs are supported:
//
// %s print the error. If the error has a Cause it will be
// printed recursively.
// %v see %s
// %+v extended format. Each Frame of the error's StackTrace will
// be printed in detail.
//
// Retrieving the stack trace of an error or wrapper
//
// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
// invoked. This information can be retrieved with the following interface:
//
// type stackTracer interface {
// StackTrace() errors.StackTrace
// }
//
// The returned errors.StackTrace type is defined as
//
// type StackTrace []Frame
//
// The Frame type represents a call site in the stack trace. Frame supports
// the fmt.Formatter interface that can be used for printing information about
// the stack trace of this error. For example:
//
// if err, ok := err.(stackTracer); ok {
// for _, f := range err.StackTrace() {
// fmt.Printf("%+s:%d", f)
// }
// }
//
// Although the stackTracer interface is not exported by this package, it is
// considered a part of its stable public interface.
//
// See the documentation for Frame.Format for more details.
package errors
import (
"fmt"
"io"
)
// New returns an error with the supplied message.
// New also records the stack trace at the point it was called.
func New(message string) error {
return &fundamental{
msg: message,
stack: callers(),
}
}
// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
// Errorf also records the stack trace at the point it was called.
func Errorf(format string, args ...interface{}) error {
return &fundamental{
msg: fmt.Sprintf(format, args...),
stack: callers(),
}
}
// fundamental is an error that has a message and a stack, but no caller.
type fundamental struct {
msg string
*stack
}
func (f *fundamental) Error() string { return f.msg }
func (f *fundamental) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
io.WriteString(s, f.msg)
f.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, f.msg)
case 'q':
fmt.Fprintf(s, "%q", f.msg)
}
}
// WithStack annotates err with a stack trace at the point WithStack was called.
// If err is nil, WithStack returns nil.
func WithStack(err error) error {
if err == nil {
return nil
}
return &withStack{
err,
callers(),
}
}
type withStack struct {
error
*stack
}
func (w *withStack) Cause() error { return w.error }
func (w *withStack) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v", w.Cause())
w.stack.Format(s, verb)
return
}
fallthrough
case 's':
io.WriteString(s, w.Error())
case 'q':
fmt.Fprintf(s, "%q", w.Error())
}
}
// Wrap returns an error annotating err with a stack trace
// at the point Wrap is called, and the supplied message.
// If err is nil, Wrap returns nil.
func Wrap(err error, message string) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: message,
}
return &withStack{
err,
callers(),
}
}
// Wrapf returns an error annotating err with a stack trace
// at the point Wrapf is called, and the format specifier.
// If err is nil, Wrapf returns nil.
func Wrapf(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
err = &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
return &withStack{
err,
callers(),
}
}
// WithMessage annotates err with a new message.
// If err is nil, WithMessage returns nil.
func WithMessage(err error, message string) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: message,
}
}
// WithMessagef annotates err with the format specifier.
// If err is nil, WithMessagef returns nil.
func WithMessagef(err error, format string, args ...interface{}) error {
if err == nil {
return nil
}
return &withMessage{
cause: err,
msg: fmt.Sprintf(format, args...),
}
}
type withMessage struct {
cause error
msg string
}
func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
func (w *withMessage) Cause() error { return w.cause }
func (w *withMessage) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
if s.Flag('+') {
fmt.Fprintf(s, "%+v\n", w.Cause())
io.WriteString(s, w.msg)
return
}
fallthrough
case 's', 'q':
io.WriteString(s, w.Error())
}
}
// Cause returns the underlying cause of the error, if possible.
// An error value has a cause if it implements the following
// interface:
//
// type causer interface {
// Cause() error
// }
//
// If the error does not implement Cause, the original error will
// be returned. If the error is nil, nil will be returned without further
// investigation.
func Cause(err error) error {
type causer interface {
Cause() error
}
for err != nil {
cause, ok := err.(causer)
if !ok {
break
}
err = cause.Cause()
}
return err
}

147
vendor/github.com/pkg/errors/stack.go generated vendored
View File

@ -1,147 +0,0 @@
package errors
import (
"fmt"
"io"
"path"
"runtime"
"strings"
)
// Frame represents a program counter inside a stack frame.
type Frame uintptr
// pc returns the program counter for this frame;
// multiple frames may have the same PC value.
func (f Frame) pc() uintptr { return uintptr(f) - 1 }
// file returns the full path to the file that contains the
// function for this Frame's pc.
func (f Frame) file() string {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return "unknown"
}
file, _ := fn.FileLine(f.pc())
return file
}
// line returns the line number of source code of the
// function for this Frame's pc.
func (f Frame) line() int {
fn := runtime.FuncForPC(f.pc())
if fn == nil {
return 0
}
_, line := fn.FileLine(f.pc())
return line
}
// Format formats the frame according to the fmt.Formatter interface.
//
// %s source file
// %d source line
// %n function name
// %v equivalent to %s:%d
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+s function name and path of source file relative to the compile time
// GOPATH separated by \n\t (<funcname>\n\t<path>)
// %+v equivalent to %+s:%d
func (f Frame) Format(s fmt.State, verb rune) {
switch verb {
case 's':
switch {
case s.Flag('+'):
pc := f.pc()
fn := runtime.FuncForPC(pc)
if fn == nil {
io.WriteString(s, "unknown")
} else {
file, _ := fn.FileLine(pc)
fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
}
default:
io.WriteString(s, path.Base(f.file()))
}
case 'd':
fmt.Fprintf(s, "%d", f.line())
case 'n':
name := runtime.FuncForPC(f.pc()).Name()
io.WriteString(s, funcname(name))
case 'v':
f.Format(s, 's')
io.WriteString(s, ":")
f.Format(s, 'd')
}
}
// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
type StackTrace []Frame
// Format formats the stack of Frames according to the fmt.Formatter interface.
//
// %s lists source files for each Frame in the stack
// %v lists the source file and line number for each Frame in the stack
//
// Format accepts flags that alter the printing of some verbs, as follows:
//
// %+v Prints filename, function, and line number for each Frame in the stack.
func (st StackTrace) Format(s fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case s.Flag('+'):
for _, f := range st {
fmt.Fprintf(s, "\n%+v", f)
}
case s.Flag('#'):
fmt.Fprintf(s, "%#v", []Frame(st))
default:
fmt.Fprintf(s, "%v", []Frame(st))
}
case 's':
fmt.Fprintf(s, "%s", []Frame(st))
}
}
// stack represents a stack of program counters.
type stack []uintptr
func (s *stack) Format(st fmt.State, verb rune) {
switch verb {
case 'v':
switch {
case st.Flag('+'):
for _, pc := range *s {
f := Frame(pc)
fmt.Fprintf(st, "\n%+v", f)
}
}
}
}
func (s *stack) StackTrace() StackTrace {
f := make([]Frame, len(*s))
for i := 0; i < len(f); i++ {
f[i] = Frame((*s)[i])
}
return f
}
func callers() *stack {
const depth = 32
var pcs [depth]uintptr
n := runtime.Callers(3, pcs[:])
var st stack = pcs[0:n]
return &st
}
// funcname removes the path prefix component of a function's name reported by func.Name().
func funcname(name string) string {
i := strings.LastIndex(name, "/")
name = name[i+1:]
i = strings.Index(name, ".")
return name[i+1:]
}

8
vendor/modules.txt vendored
View File

@ -53,12 +53,10 @@ github.com/bugsnag/bugsnag-go/headers
github.com/bugsnag/bugsnag-go/sessions
# github.com/bugsnag/panicwrap v1.2.0
github.com/bugsnag/panicwrap
# github.com/certifi/gocertifi v0.0.0-20180118203423-deb3ae2ef261
github.com/certifi/gocertifi
# github.com/davecgh/go-spew v1.1.1
github.com/davecgh/go-spew/spew
# github.com/getsentry/raven-go v0.2.0
github.com/getsentry/raven-go
# github.com/getsentry/sentry-go v0.2.1
github.com/getsentry/sentry-go
# github.com/go-ole/go-ole v1.2.2
github.com/go-ole/go-ole
github.com/go-ole/go-ole/oleutil
@ -99,8 +97,6 @@ github.com/newrelic/go-agent/internal/jsonx
github.com/newrelic/go-agent/internal/sysinfo
# github.com/pborman/uuid v0.0.0-20180906182336-adf5a7427709
github.com/pborman/uuid
# github.com/pkg/errors v0.8.1
github.com/pkg/errors
# github.com/pmezard/go-difflib v1.0.0
github.com/pmezard/go-difflib/difflib
# github.com/prometheus/client_golang v0.9.2