summaryrefslogtreecommitdiffstats
path: root/vendor/gopkg.in/airbrake
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/gopkg.in/airbrake')
-rw-r--r--vendor/gopkg.in/airbrake/gobrake.v2/LICENSE27
-rw-r--r--vendor/gopkg.in/airbrake/gobrake.v2/gobrake.go16
-rw-r--r--vendor/gopkg.in/airbrake/gobrake.v2/notice.go105
-rw-r--r--vendor/gopkg.in/airbrake/gobrake.v2/notifier.go280
-rw-r--r--vendor/gopkg.in/airbrake/gobrake.v2/util.go59
5 files changed, 487 insertions, 0 deletions
diff --git a/vendor/gopkg.in/airbrake/gobrake.v2/LICENSE b/vendor/gopkg.in/airbrake/gobrake.v2/LICENSE
new file mode 100644
index 00000000..d64c10ef
--- /dev/null
+++ b/vendor/gopkg.in/airbrake/gobrake.v2/LICENSE
@@ -0,0 +1,27 @@
+Copyright (c) 2014 The Gobrake Authors. 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 Google Inc. 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.
diff --git a/vendor/gopkg.in/airbrake/gobrake.v2/gobrake.go b/vendor/gopkg.in/airbrake/gobrake.v2/gobrake.go
new file mode 100644
index 00000000..23efe414
--- /dev/null
+++ b/vendor/gopkg.in/airbrake/gobrake.v2/gobrake.go
@@ -0,0 +1,16 @@
+package gobrake
+
+import (
+ "log"
+ "os"
+)
+
+var logger *log.Logger
+
+func init() {
+ SetLogger(log.New(os.Stderr, "gobrake: ", log.LstdFlags))
+}
+
+func SetLogger(l *log.Logger) {
+ logger = l
+}
diff --git a/vendor/gopkg.in/airbrake/gobrake.v2/notice.go b/vendor/gopkg.in/airbrake/gobrake.v2/notice.go
new file mode 100644
index 00000000..06bc771a
--- /dev/null
+++ b/vendor/gopkg.in/airbrake/gobrake.v2/notice.go
@@ -0,0 +1,105 @@
+package gobrake
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+)
+
+var defaultContext map[string]interface{}
+
+func getDefaultContext() map[string]interface{} {
+ if defaultContext != nil {
+ return defaultContext
+ }
+
+ defaultContext = map[string]interface{}{
+ "notifier": map[string]interface{}{
+ "name": "gobrake",
+ "version": "2.0.4",
+ "url": "https://github.com/airbrake/gobrake",
+ },
+
+ "language": runtime.Version(),
+ "os": runtime.GOOS,
+ "architecture": runtime.GOARCH,
+ }
+ if s, err := os.Hostname(); err == nil {
+ defaultContext["hostname"] = s
+ }
+ if s := os.Getenv("GOPATH"); s != "" {
+ list := filepath.SplitList(s)
+ // TODO: multiple root dirs?
+ defaultContext["rootDirectory"] = list[0]
+ }
+ return defaultContext
+}
+
+type Error struct {
+ Type string `json:"type"`
+ Message string `json:"message"`
+ Backtrace []StackFrame `json:"backtrace"`
+}
+
+type Notice struct {
+ Errors []Error `json:"errors"`
+ Context map[string]interface{} `json:"context"`
+ Env map[string]interface{} `json:"environment"`
+ Session map[string]interface{} `json:"session"`
+ Params map[string]interface{} `json:"params"`
+}
+
+func (n *Notice) String() string {
+ if len(n.Errors) == 0 {
+ return "Notice<no errors>"
+ }
+ e := n.Errors[0]
+ return fmt.Sprintf("Notice<%s: %s>", e.Type, e.Message)
+}
+
+func NewNotice(e interface{}, req *http.Request, depth int) *Notice {
+ notice := &Notice{
+ Errors: []Error{{
+ Type: fmt.Sprintf("%T", e),
+ Message: fmt.Sprint(e),
+ Backtrace: stack(depth),
+ }},
+ Context: map[string]interface{}{},
+ Env: map[string]interface{}{},
+ Session: map[string]interface{}{},
+ Params: map[string]interface{}{},
+ }
+
+ for k, v := range getDefaultContext() {
+ notice.Context[k] = v
+ }
+
+ if req != nil {
+ notice.Context["url"] = req.URL.String()
+ if ua := req.Header.Get("User-Agent"); ua != "" {
+ notice.Context["userAgent"] = ua
+ }
+
+ for k, v := range req.Header {
+ if len(v) == 1 {
+ notice.Env[k] = v[0]
+ } else {
+ notice.Env[k] = v
+ }
+ }
+
+ if err := req.ParseForm(); err == nil {
+ for k, v := range req.Form {
+ if len(v) == 1 {
+ notice.Params[k] = v[0]
+ } else {
+ notice.Params[k] = v
+ }
+ }
+ }
+ }
+
+ return notice
+}
diff --git a/vendor/gopkg.in/airbrake/gobrake.v2/notifier.go b/vendor/gopkg.in/airbrake/gobrake.v2/notifier.go
new file mode 100644
index 00000000..e409321f
--- /dev/null
+++ b/vendor/gopkg.in/airbrake/gobrake.v2/notifier.go
@@ -0,0 +1,280 @@
+package gobrake // import "gopkg.in/airbrake/gobrake.v2"
+
+import (
+ "bytes"
+ "crypto/tls"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net"
+ "net/http"
+ "path/filepath"
+ "strings"
+ "sync"
+ "time"
+)
+
+const defaultAirbrakeHost = "https://airbrake.io"
+const waitTimeout = 5 * time.Second
+const httpStatusTooManyRequests = 429
+
+var (
+ errClosed = errors.New("gobrake: notifier is closed")
+ errRateLimited = errors.New("gobrake: rate limited")
+)
+
+var httpClient = &http.Client{
+ Transport: &http.Transport{
+ Proxy: http.ProxyFromEnvironment,
+ Dial: (&net.Dialer{
+ Timeout: 15 * time.Second,
+ KeepAlive: 30 * time.Second,
+ }).Dial,
+ TLSHandshakeTimeout: 10 * time.Second,
+ TLSClientConfig: &tls.Config{
+ ClientSessionCache: tls.NewLRUClientSessionCache(1024),
+ },
+ MaxIdleConnsPerHost: 10,
+ ResponseHeaderTimeout: 10 * time.Second,
+ },
+ Timeout: 10 * time.Second,
+}
+
+var buffers = sync.Pool{
+ New: func() interface{} {
+ return new(bytes.Buffer)
+ },
+}
+
+type filter func(*Notice) *Notice
+
+type Notifier struct {
+ // http.Client that is used to interact with Airbrake API.
+ Client *http.Client
+
+ projectId int64
+ projectKey string
+ createNoticeURL string
+
+ filters []filter
+
+ wg sync.WaitGroup
+ noticeCh chan *Notice
+ closed chan struct{}
+}
+
+func NewNotifier(projectId int64, projectKey string) *Notifier {
+ n := &Notifier{
+ Client: httpClient,
+
+ projectId: projectId,
+ projectKey: projectKey,
+ createNoticeURL: getCreateNoticeURL(defaultAirbrakeHost, projectId, projectKey),
+
+ filters: []filter{noticeBacktraceFilter},
+
+ noticeCh: make(chan *Notice, 1000),
+ closed: make(chan struct{}),
+ }
+ for i := 0; i < 10; i++ {
+ go n.worker()
+ }
+ return n
+}
+
+// Sets Airbrake host name. Default is https://airbrake.io.
+func (n *Notifier) SetHost(h string) {
+ n.createNoticeURL = getCreateNoticeURL(h, n.projectId, n.projectKey)
+}
+
+// AddFilter adds filter that can modify or ignore notice.
+func (n *Notifier) AddFilter(fn filter) {
+ n.filters = append(n.filters, fn)
+}
+
+// Notify notifies Airbrake about the error.
+func (n *Notifier) Notify(e interface{}, req *http.Request) {
+ notice := n.Notice(e, req, 1)
+ n.SendNoticeAsync(notice)
+}
+
+// Notice returns Aibrake notice created from error and request. depth
+// determines which call frame to use when constructing backtrace.
+func (n *Notifier) Notice(err interface{}, req *http.Request, depth int) *Notice {
+ return NewNotice(err, req, depth+3)
+}
+
+type sendResponse struct {
+ Id string `json:"id"`
+}
+
+// SendNotice sends notice to Airbrake.
+func (n *Notifier) SendNotice(notice *Notice) (string, error) {
+ for _, fn := range n.filters {
+ notice = fn(notice)
+ if notice == nil {
+ // Notice is ignored.
+ return "", nil
+ }
+ }
+
+ buf := buffers.Get().(*bytes.Buffer)
+ defer buffers.Put(buf)
+
+ buf.Reset()
+ if err := json.NewEncoder(buf).Encode(notice); err != nil {
+ return "", err
+ }
+
+ resp, err := n.Client.Post(n.createNoticeURL, "application/json", buf)
+ if err != nil {
+ return "", err
+ }
+ defer resp.Body.Close()
+
+ buf.Reset()
+ _, err = buf.ReadFrom(resp.Body)
+ if err != nil {
+ return "", err
+ }
+
+ if resp.StatusCode != http.StatusCreated {
+ if resp.StatusCode == httpStatusTooManyRequests {
+ return "", errRateLimited
+ }
+ err := fmt.Errorf("gobrake: got response status=%q, wanted 201 CREATED", resp.Status)
+ return "", err
+ }
+
+ var sendResp sendResponse
+ err = json.NewDecoder(buf).Decode(&sendResp)
+ if err != nil {
+ return "", err
+ }
+
+ return sendResp.Id, nil
+}
+
+func (n *Notifier) sendNotice(notice *Notice) {
+ if _, err := n.SendNotice(notice); err != nil && err != errRateLimited {
+ logger.Printf("gobrake failed reporting notice=%q: %s", notice, err)
+ }
+ n.wg.Done()
+}
+
+// SendNoticeAsync acts as SendNotice, but sends notice asynchronously
+// and pending notices can be flushed with Flush.
+func (n *Notifier) SendNoticeAsync(notice *Notice) {
+ select {
+ case <-n.closed:
+ return
+ default:
+ }
+
+ n.wg.Add(1)
+ select {
+ case n.noticeCh <- notice:
+ default:
+ n.wg.Done()
+ logger.Printf(
+ "notice=%q is ignored, because queue is full (len=%d)",
+ notice, len(n.noticeCh),
+ )
+ }
+}
+
+func (n *Notifier) worker() {
+ for {
+ select {
+ case notice := <-n.noticeCh:
+ n.sendNotice(notice)
+ case <-n.closed:
+ select {
+ case notice := <-n.noticeCh:
+ n.sendNotice(notice)
+ default:
+ return
+ }
+ }
+ }
+}
+
+// NotifyOnPanic notifies Airbrake about the panic and should be used
+// with defer statement.
+func (n *Notifier) NotifyOnPanic() {
+ if v := recover(); v != nil {
+ notice := n.Notice(v, nil, 3)
+ n.SendNotice(notice)
+ panic(v)
+ }
+}
+
+// Flush waits for pending requests to finish.
+func (n *Notifier) Flush() {
+ n.waitTimeout(waitTimeout)
+}
+
+// Deprecated. Use CloseTimeout instead.
+func (n *Notifier) WaitAndClose(timeout time.Duration) error {
+ return n.CloseTimeout(timeout)
+}
+
+// CloseTimeout waits for pending requests to finish and then closes the notifier.
+func (n *Notifier) CloseTimeout(timeout time.Duration) error {
+ select {
+ case <-n.closed:
+ default:
+ close(n.closed)
+ }
+ return n.waitTimeout(timeout)
+}
+
+func (n *Notifier) waitTimeout(timeout time.Duration) error {
+ done := make(chan struct{})
+ go func() {
+ n.wg.Wait()
+ close(done)
+ }()
+
+ select {
+ case <-done:
+ return nil
+ case <-time.After(timeout):
+ return fmt.Errorf("Wait timed out after %s", timeout)
+ }
+}
+
+func (n *Notifier) Close() error {
+ return n.CloseTimeout(waitTimeout)
+}
+
+func getCreateNoticeURL(host string, projectId int64, key string) string {
+ return fmt.Sprintf(
+ "%s/api/v3/projects/%d/notices?key=%s",
+ host, projectId, key,
+ )
+}
+
+func noticeBacktraceFilter(notice *Notice) *Notice {
+ v, ok := notice.Context["rootDirectory"]
+ if !ok {
+ return notice
+ }
+
+ dir, ok := v.(string)
+ if !ok {
+ return notice
+ }
+
+ dir = filepath.Join(dir, "src")
+ for i := range notice.Errors {
+ replaceRootDirectory(notice.Errors[i].Backtrace, dir)
+ }
+ return notice
+}
+
+func replaceRootDirectory(backtrace []StackFrame, rootDir string) {
+ for i := range backtrace {
+ backtrace[i].File = strings.Replace(backtrace[i].File, rootDir, "[PROJECT_ROOT]", 1)
+ }
+}
diff --git a/vendor/gopkg.in/airbrake/gobrake.v2/util.go b/vendor/gopkg.in/airbrake/gobrake.v2/util.go
new file mode 100644
index 00000000..c05c0331
--- /dev/null
+++ b/vendor/gopkg.in/airbrake/gobrake.v2/util.go
@@ -0,0 +1,59 @@
+package gobrake
+
+import (
+ "runtime"
+ "strings"
+)
+
+func stackFilter(packageName, funcName string, file string, line int) bool {
+ return packageName == "runtime" && funcName == "panic"
+}
+
+type StackFrame struct {
+ File string `json:"file"`
+ Line int `json:"line"`
+ Func string `json:"function"`
+}
+
+func stack(depth int) []StackFrame {
+ stack := []StackFrame{}
+ for i := depth; ; i++ {
+ pc, file, line, ok := runtime.Caller(i)
+ if !ok {
+ break
+ }
+ packageName, funcName := packageFuncName(pc)
+ if stackFilter(packageName, funcName, file, line) {
+ stack = stack[:0]
+ continue
+ }
+ stack = append(stack, StackFrame{
+ File: file,
+ Line: line,
+ Func: funcName,
+ })
+ }
+
+ return stack
+}
+
+func packageFuncName(pc uintptr) (string, string) {
+ f := runtime.FuncForPC(pc)
+ if f == nil {
+ return "", ""
+ }
+
+ packageName := ""
+ funcName := f.Name()
+
+ if ind := strings.LastIndex(funcName, "/"); ind > 0 {
+ packageName += funcName[:ind+1]
+ funcName = funcName[ind+1:]
+ }
+ if ind := strings.Index(funcName, "."); ind > 0 {
+ packageName += funcName[:ind]
+ funcName = funcName[ind+1:]
+ }
+
+ return packageName, funcName
+}