mirror of
https://github.com/consbio/mbtileserver.git
synced 2024-09-11 07:15:24 +03:00
Add missing deps (again)
This commit is contained in:
parent
4ed24c4380
commit
45249b355e
3
vendor/github.com/certifi/gocertifi/LICENSE
generated
vendored
Normal file
3
vendor/github.com/certifi/gocertifi/LICENSE
generated
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
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/.
|
60
vendor/github.com/certifi/gocertifi/README.md
generated
vendored
Normal file
60
vendor/github.com/certifi/gocertifi/README.md
generated
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
# 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.
|
5330
vendor/github.com/certifi/gocertifi/certifi.go
generated
vendored
Normal file
5330
vendor/github.com/certifi/gocertifi/certifi.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
20
vendor/github.com/certifi/gocertifi/tasks.py
generated
vendored
Normal file
20
vendor/github.com/certifi/gocertifi/tasks.py
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
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))
|
13
vendor/github.com/getsentry/raven-go/Dockerfile.test
generated
vendored
Normal file
13
vendor/github.com/getsentry/raven-go/Dockerfile.test
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
FROM golang:1.7
|
||||
|
||||
RUN mkdir -p /go/src/github.com/getsentry/raven-go
|
||||
WORKDIR /go/src/github.com/getsentry/raven-go
|
||||
ENV GOPATH /go
|
||||
|
||||
RUN go install -race std && go get golang.org/x/tools/cmd/cover
|
||||
|
||||
COPY . /go/src/github.com/getsentry/raven-go
|
||||
|
||||
RUN go get -v ./...
|
||||
|
||||
CMD ["./runtests.sh"]
|
28
vendor/github.com/getsentry/raven-go/LICENSE
generated
vendored
Normal file
28
vendor/github.com/getsentry/raven-go/LICENSE
generated
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
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.
|
13
vendor/github.com/getsentry/raven-go/README.md
generated
vendored
Normal file
13
vendor/github.com/getsentry/raven-go/README.md
generated
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
# raven [![Build Status](https://travis-ci.org/getsentry/raven-go.png?branch=master)](https://travis-ci.org/getsentry/raven-go)
|
||||
|
||||
raven is a Go client 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.getsentry.com/hosted/clients/go/)
|
||||
|
||||
## Installation
|
||||
|
||||
```text
|
||||
go get github.com/getsentry/raven-go
|
||||
```
|
776
vendor/github.com/getsentry/raven-go/client.go
generated
vendored
Normal file
776
vendor/github.com/getsentry/raven-go/client.go
generated
vendored
Normal file
@ -0,0 +1,776 @@
|
||||
// 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"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/certifi/gocertifi"
|
||||
)
|
||||
|
||||
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")
|
||||
ErrMissingPrivateKey = errors.New("raven: dsn missing private key")
|
||||
ErrMissingProjectID = errors.New("raven: dsn missing project id")
|
||||
)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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 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 map[string]interface{} `json:"extra,omitempty"`
|
||||
|
||||
Interfaces []Interface `json:"-"`
|
||||
}
|
||||
|
||||
// NewPacket constructs a packet with the specified message and interfaces.
|
||||
func NewPacket(message string, interfaces ...Interface) *Packet {
|
||||
extra := map[string]interface{}{
|
||||
"runtime.Version": runtime.Version(),
|
||||
"runtime.NumCPU": runtime.NumCPU(),
|
||||
"runtime.GOMAXPROCS": runtime.GOMAXPROCS(0), // 0 just returns the current value
|
||||
"runtime.NumGoroutine": runtime.NumGoroutine(),
|
||||
}
|
||||
return &Packet{
|
||||
Message: message,
|
||||
Interfaces: interfaces,
|
||||
Extra: 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 {
|
||||
packetJSON, _ := json.Marshal(packet)
|
||||
|
||||
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, _ := json.Marshal(interfaces)
|
||||
packetJSON[len(packetJSON)-1] = ','
|
||||
packetJSON = append(packetJSON, interfaceJSON[1:]...)
|
||||
}
|
||||
|
||||
return packetJSON
|
||||
}
|
||||
|
||||
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{
|
||||
TLSClientConfig: &tls.Config{RootCAs: rootCAs},
|
||||
},
|
||||
}
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func newClient(tags map[string]string) *Client {
|
||||
client := &Client{
|
||||
Transport: newTransport(),
|
||||
Tags: tags,
|
||||
context: &context{},
|
||||
queue: make(chan *outgoingPacket, MaxQueueBuffer),
|
||||
}
|
||||
go client.worker()
|
||||
client.SetDSN(os.Getenv("SENTRY_DSN"))
|
||||
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
|
||||
includePaths []string
|
||||
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
|
||||
}
|
||||
|
||||
// Initialize a default *Client instance
|
||||
var DefaultClient = newClient(nil)
|
||||
|
||||
// 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, ok := uri.User.Password()
|
||||
if !ok {
|
||||
return ErrMissingPrivateKey
|
||||
}
|
||||
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()
|
||||
|
||||
client.authHeader = fmt.Sprintf("Sentry sentry_version=4, sentry_key=%s, sentry_secret=%s", publicKey, secretKey)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
// 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) }
|
||||
|
||||
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) {
|
||||
if client == nil {
|
||||
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)
|
||||
|
||||
ch = make(chan error, 1)
|
||||
|
||||
// Merge capture tags and client tags
|
||||
packet.AddTags(captureTags)
|
||||
packet.AddTags(client.Tags)
|
||||
packet.AddTags(client.context.tags)
|
||||
|
||||
// Initialize any required packet fields
|
||||
client.mu.RLock()
|
||||
projectID := client.projectID
|
||||
release := client.release
|
||||
environment := client.environment
|
||||
client.mu.RUnlock()
|
||||
|
||||
err := packet.Init(projectID)
|
||||
if err != nil {
|
||||
ch <- err
|
||||
client.wg.Done()
|
||||
return
|
||||
}
|
||||
|
||||
packet.Release = release
|
||||
packet.Environment = environment
|
||||
|
||||
outgoingPacket := &outgoingPacket{packet, ch}
|
||||
|
||||
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 ""
|
||||
}
|
||||
|
||||
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 ""
|
||||
}
|
||||
|
||||
packet := NewPacket(message, append(append(interfaces, client.context.interfaces()...), &Message{message, nil})...)
|
||||
eventID, ch := client.Capture(packet, tags)
|
||||
<-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 ""
|
||||
}
|
||||
|
||||
packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, NewStacktrace(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 ""
|
||||
}
|
||||
|
||||
packet := NewPacket(err.Error(), append(append(interfaces, client.context.interfaces()...), NewException(err, NewStacktrace(1, 3, client.includePaths)))...)
|
||||
eventID, ch := client.Capture(packet, tags)
|
||||
<-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:
|
||||
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
|
||||
default:
|
||||
rvalStr := fmt.Sprint(rval)
|
||||
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:
|
||||
packet = NewPacket(rval.Error(), append(append(interfaces, client.context.interfaces()...), NewException(rval, NewStacktrace(2, 3, client.includePaths)))...)
|
||||
default:
|
||||
rvalStr := fmt.Sprint(rval)
|
||||
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)
|
||||
<-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.context.SetUser(u) }
|
||||
func (c *Client) SetHttpContext(h *Http) { c.context.SetHttp(h) }
|
||||
func (c *Client) SetTagsContext(t map[string]string) { c.context.SetTags(t) }
|
||||
func (c *Client) ClearContext() { 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 := serializedPacket(packet)
|
||||
req, _ := http.NewRequest("POST", url, body)
|
||||
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", res.StatusCode)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func serializedPacket(packet *Packet) (r io.Reader, contentType string) {
|
||||
packetJSON := packet.JSON()
|
||||
|
||||
// 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"
|
||||
}
|
||||
return bytes.NewReader(packetJSON), "application/json"
|
||||
}
|
||||
|
||||
var hostname string
|
||||
|
||||
func init() {
|
||||
hostname, _ = os.Hostname()
|
||||
}
|
41
vendor/github.com/getsentry/raven-go/exception.go
generated
vendored
Normal file
41
vendor/github.com/getsentry/raven-go/exception.go
generated
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
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()
|
||||
}
|
84
vendor/github.com/getsentry/raven-go/http.go
generated
vendored
Normal file
84
vendor/github.com/getsentry/raven-go/http.go
generated
vendored
Normal file
@ -0,0 +1,84 @@
|
||||
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, ",")
|
||||
}
|
||||
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 func(w http.ResponseWriter, r *http.Request) {
|
||||
defer func() {
|
||||
if rval := recover(); rval != nil {
|
||||
debug.PrintStack()
|
||||
rvalStr := fmt.Sprint(rval)
|
||||
packet := NewPacket(rvalStr, NewException(errors.New(rvalStr), NewStacktrace(2, 3, nil)), NewHttp(r))
|
||||
Capture(packet, nil)
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
}()
|
||||
|
||||
handler(w, r)
|
||||
}
|
||||
}
|
49
vendor/github.com/getsentry/raven-go/interfaces.go
generated
vendored
Normal file
49
vendor/github.com/getsentry/raven-go/interfaces.go
generated
vendored
Normal file
@ -0,0 +1,49 @@
|
||||
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" }
|
4
vendor/github.com/getsentry/raven-go/runtests.sh
generated
vendored
Executable file
4
vendor/github.com/getsentry/raven-go/runtests.sh
generated
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
#!/bin/bash
|
||||
go test -race ./...
|
||||
go test -cover ./...
|
||||
go test -v ./...
|
213
vendor/github.com/getsentry/raven-go/stacktrace.go
generated
vendored
Normal file
213
vendor/github.com/getsentry/raven-go/stacktrace.go
generated
vendored
Normal file
@ -0,0 +1,213 @@
|
||||
// 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"
|
||||
)
|
||||
|
||||
// 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"`
|
||||
}
|
||||
|
||||
// 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
|
||||
for i := 1 + skip; ; i++ {
|
||||
pc, file, line, ok := runtime.Caller(i)
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
frame := NewStacktraceFrame(pc, file, line, context, appPackagePrefixes)
|
||||
if frame != nil {
|
||||
frames = append(frames, frame)
|
||||
}
|
||||
}
|
||||
// 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, file string, line, context int, appPackagePrefixes []string) *StacktraceFrame {
|
||||
frame := &StacktraceFrame{AbsolutePath: file, Filename: trimPath(file), Lineno: line, InApp: false}
|
||||
frame.Module, frame.Function = functionName(pc)
|
||||
|
||||
// `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 := fileContext(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, _ := fileContext(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(pc uintptr) (pack string, name string) {
|
||||
fn := runtime.FuncForPC(pc)
|
||||
if fn == nil {
|
||||
return
|
||||
}
|
||||
name = fn.Name()
|
||||
// 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
|
||||
}
|
||||
|
||||
var fileCacheLock sync.Mutex
|
||||
var fileCache = make(map[string][][]byte)
|
||||
|
||||
func fileContext(filename string, line, context int) ([][]byte, int) {
|
||||
fileCacheLock.Lock()
|
||||
defer fileCacheLock.Unlock()
|
||||
lines, ok := fileCache[filename]
|
||||
if !ok {
|
||||
data, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return nil, 0
|
||||
}
|
||||
lines = bytes.Split(data, []byte{'\n'})
|
||||
fileCache[filename] = lines
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
20
vendor/github.com/getsentry/raven-go/writer.go
generated
vendored
Normal file
20
vendor/github.com/getsentry/raven-go/writer.go
generated
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
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
|
||||
}
|
Loading…
Reference in New Issue
Block a user