diff options
Diffstat (limited to 'vendor/gopkg.in')
-rw-r--r-- | vendor/gopkg.in/airbrake/gobrake.v2/LICENSE | 27 | ||||
-rw-r--r-- | vendor/gopkg.in/airbrake/gobrake.v2/gobrake.go | 16 | ||||
-rw-r--r-- | vendor/gopkg.in/airbrake/gobrake.v2/notice.go | 105 | ||||
-rw-r--r-- | vendor/gopkg.in/airbrake/gobrake.v2/notifier.go | 280 | ||||
-rw-r--r-- | vendor/gopkg.in/airbrake/gobrake.v2/util.go | 59 | ||||
-rw-r--r-- | vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/LICENSE | 21 | ||||
-rw-r--r-- | vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/airbrake.go | 71 |
7 files changed, 579 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 +} diff --git a/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/LICENSE b/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/LICENSE new file mode 100644 index 00000000..a4282b2a --- /dev/null +++ b/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Gemnasium + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/airbrake.go b/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/airbrake.go new file mode 100644 index 00000000..a92e01ed --- /dev/null +++ b/vendor/gopkg.in/gemnasium/logrus-airbrake-hook.v2/airbrake.go @@ -0,0 +1,71 @@ +package airbrake // import "gopkg.in/gemnasium/logrus-airbrake-hook.v2" + +import ( + "errors" + "fmt" + "net/http" + "os" + + "github.com/Sirupsen/logrus" + "gopkg.in/airbrake/gobrake.v2" +) + +// AirbrakeHook to send exceptions to an exception-tracking service compatible +// with the Airbrake API. +type airbrakeHook struct { + Airbrake *gobrake.Notifier +} + +func NewHook(projectID int64, apiKey, env string) *airbrakeHook { + airbrake := gobrake.NewNotifier(projectID, apiKey) + airbrake.AddFilter(func(notice *gobrake.Notice) *gobrake.Notice { + if env == "development" { + return nil + } + notice.Context["environment"] = env + return notice + }) + hook := &airbrakeHook{ + Airbrake: airbrake, + } + return hook +} + +func (hook *airbrakeHook) Fire(entry *logrus.Entry) error { + var notifyErr error + err, ok := entry.Data["error"].(error) + if ok { + notifyErr = err + } else { + notifyErr = errors.New(entry.Message) + } + var req *http.Request + for k, v := range entry.Data { + if r, ok := v.(*http.Request); ok { + req = r + delete(entry.Data, k) + break + } + } + notice := hook.Airbrake.Notice(notifyErr, req, 3) + for k, v := range entry.Data { + notice.Context[k] = fmt.Sprintf("%s", v) + } + + hook.sendNotice(notice) + return nil +} + +func (hook *airbrakeHook) sendNotice(notice *gobrake.Notice) { + if _, err := hook.Airbrake.SendNotice(notice); err != nil { + fmt.Fprintf(os.Stderr, "Failed to send error to Airbrake: %v\n", err) + } +} + +func (hook *airbrakeHook) Levels() []logrus.Level { + return []logrus.Level{ + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, + } +} |