From b8baef7b8f086919fa777d38f3f766d24b53510f Mon Sep 17 00:00:00 2001 From: Jesse Duffield Date: Sat, 29 Jun 2019 20:52:49 +1000 Subject: use fork of roll that doesn't care about errors --- vendor/github.com/heroku/rollrus/LICENSE | 22 -- vendor/github.com/heroku/rollrus/rollrus.go | 287 --------------------- vendor/github.com/jesseduffield/roll/LICENSE | 22 ++ vendor/github.com/jesseduffield/roll/client.go | 242 +++++++++++++++++ vendor/github.com/jesseduffield/roll/stack.go | 98 +++++++ vendor/github.com/jesseduffield/rollrus/LICENSE | 22 ++ vendor/github.com/jesseduffield/rollrus/rollrus.go | 287 +++++++++++++++++++++ vendor/github.com/stvp/roll/LICENSE | 22 -- vendor/github.com/stvp/roll/client.go | 240 ----------------- vendor/github.com/stvp/roll/stack.go | 98 ------- 10 files changed, 671 insertions(+), 669 deletions(-) delete mode 100644 vendor/github.com/heroku/rollrus/LICENSE delete mode 100644 vendor/github.com/heroku/rollrus/rollrus.go create mode 100644 vendor/github.com/jesseduffield/roll/LICENSE create mode 100644 vendor/github.com/jesseduffield/roll/client.go create mode 100644 vendor/github.com/jesseduffield/roll/stack.go create mode 100644 vendor/github.com/jesseduffield/rollrus/LICENSE create mode 100644 vendor/github.com/jesseduffield/rollrus/rollrus.go delete mode 100644 vendor/github.com/stvp/roll/LICENSE delete mode 100644 vendor/github.com/stvp/roll/client.go delete mode 100644 vendor/github.com/stvp/roll/stack.go (limited to 'vendor') diff --git a/vendor/github.com/heroku/rollrus/LICENSE b/vendor/github.com/heroku/rollrus/LICENSE deleted file mode 100644 index 8d4a5174d..000000000 --- a/vendor/github.com/heroku/rollrus/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -The MIT License (MIT) - -Copyright © Heroku 2014 - 2015 - -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/github.com/heroku/rollrus/rollrus.go b/vendor/github.com/heroku/rollrus/rollrus.go deleted file mode 100644 index 50dd225da..000000000 --- a/vendor/github.com/heroku/rollrus/rollrus.go +++ /dev/null @@ -1,287 +0,0 @@ -// Package rollrus combines github.com/stvp/roll with github.com/sirupsen/logrus -// via logrus.Hook mechanism, so that whenever logrus' logger.Error/f(), -// logger.Fatal/f() or logger.Panic/f() are used the messages are -// intercepted and sent to rollbar. -// -// Using SetupLogging should suffice for basic use cases that use the logrus -// singleton logger. -// -// More custom uses are supported by creating a new Hook with NewHook and -// registering that hook with the logrus Logger of choice. -// -// The levels can be customized with the WithLevels OptionFunc. -// -// Specific errors can be ignored with the WithIgnoredErrors OptionFunc. This is -// useful for ignoring errors such as context.Canceled. -// -// See the Examples in the tests for more usage. -package rollrus - -import ( - "fmt" - "os" - "time" - - "github.com/pkg/errors" - "github.com/sirupsen/logrus" - "github.com/stvp/roll" -) - -var defaultTriggerLevels = []logrus.Level{ - logrus.ErrorLevel, - logrus.FatalLevel, - logrus.PanicLevel, -} - -// Hook is a wrapper for the rollbar Client and is usable as a logrus.Hook. -type Hook struct { - roll.Client - triggers []logrus.Level - ignoredErrors map[error]struct{} - ignoreErrorFunc func(error) bool - ignoreFunc func(error, map[string]string) bool - - // only used for tests to verify whether or not a report happened. - reported bool -} - -// OptionFunc that can be passed to NewHook. -type OptionFunc func(*Hook) - -// wellKnownErrorFields are the names of the fields to be checked for values of -// type `error`, in priority order. -var wellKnownErrorFields = []string{ - logrus.ErrorKey, "err", -} - -// WithLevels is an OptionFunc that customizes the log.Levels the hook will -// report on. -func WithLevels(levels ...logrus.Level) OptionFunc { - return func(h *Hook) { - h.triggers = levels - } -} - -// WithMinLevel is an OptionFunc that customizes the log.Levels the hook will -// report on by selecting all levels more severe than the one provided. -func WithMinLevel(level logrus.Level) OptionFunc { - var levels []logrus.Level - for _, l := range logrus.AllLevels { - if l <= level { - levels = append(levels, l) - } - } - - return func(h *Hook) { - h.triggers = levels - } -} - -// WithIgnoredErrors is an OptionFunc that whitelists certain errors to prevent -// them from firing. -func WithIgnoredErrors(errors ...error) OptionFunc { - return func(h *Hook) { - for _, e := range errors { - h.ignoredErrors[e] = struct{}{} - } - } -} - -// WithIgnoreErrorFunc is an OptionFunc that receives the error that is about -// to be logged and returns true/false if it wants to fire a rollbar alert for. -func WithIgnoreErrorFunc(fn func(error) bool) OptionFunc { - return func(h *Hook) { - h.ignoreErrorFunc = fn - } -} - -// WithIgnoreFunc is an OptionFunc that receives the error and custom fields that are about -// to be logged and returns true/false if it wants to fire a rollbar alert for. -func WithIgnoreFunc(fn func(err error, fields map[string]string) bool) OptionFunc { - return func(h *Hook) { - h.ignoreFunc = fn - } -} - -// NewHook creates a hook that is intended for use with your own logrus.Logger -// instance. Uses the defualt report levels defined in wellKnownErrorFields. -func NewHook(token string, env string, opts ...OptionFunc) *Hook { - h := NewHookForLevels(token, env, defaultTriggerLevels) - - for _, o := range opts { - o(h) - } - - return h -} - -// NewHookForLevels provided by the caller. Otherwise works like NewHook. -func NewHookForLevels(token string, env string, levels []logrus.Level) *Hook { - return &Hook{ - Client: roll.New(token, env), - triggers: levels, - ignoredErrors: make(map[error]struct{}), - ignoreErrorFunc: func(error) bool { return false }, - ignoreFunc: func(error, map[string]string) bool { return false }, - } -} - -// SetupLogging for use on Heroku. If token is not an empty string a rollbar -// hook is added with the environment set to env. The log formatter is set to a -// TextFormatter with timestamps disabled. -func SetupLogging(token, env string) { - setupLogging(token, env, defaultTriggerLevels) -} - -// SetupLoggingForLevels works like SetupLogging, but allows you to -// set the levels on which to trigger this hook. -func SetupLoggingForLevels(token, env string, levels []logrus.Level) { - setupLogging(token, env, levels) -} - -func setupLogging(token, env string, levels []logrus.Level) { - logrus.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true}) - - if token != "" { - logrus.AddHook(NewHookForLevels(token, env, levels)) - } -} - -// ReportPanic attempts to report the panic to rollbar using the provided -// client and then re-panic. If it can't report the panic it will print an -// error to stderr. -func (r *Hook) ReportPanic() { - if p := recover(); p != nil { - if _, err := r.Client.Critical(fmt.Errorf("panic: %q", p), nil); err != nil { - fmt.Fprintf(os.Stderr, "reporting_panic=false err=%q\n", err) - } - panic(p) - } -} - -// ReportPanic attempts to report the panic to rollbar if the token is set -func ReportPanic(token, env string) { - if token != "" { - h := &Hook{Client: roll.New(token, env)} - h.ReportPanic() - } -} - -// Levels returns the logrus log.Levels that this hook handles -func (r *Hook) Levels() []logrus.Level { - if r.triggers == nil { - return defaultTriggerLevels - } - return r.triggers -} - -// Fire the hook. This is called by Logrus for entries that match the levels -// returned by Levels(). -func (r *Hook) Fire(entry *logrus.Entry) error { - trace, cause := extractError(entry) - if _, ok := r.ignoredErrors[cause]; ok { - return nil - } - - if r.ignoreErrorFunc(cause) { - return nil - } - - m := convertFields(entry.Data) - if _, exists := m["time"]; !exists { - m["time"] = entry.Time.Format(time.RFC3339) - } - - if r.ignoreFunc(cause, m) { - return nil - } - - return r.report(entry, cause, m, trace) -} - -func (r *Hook) report(entry *logrus.Entry, cause error, m map[string]string, trace []uintptr) (err error) { - hasTrace := len(trace) > 0 - level := entry.Level - - r.reported = true - - switch { - case hasTrace && level == logrus.FatalLevel: - _, err = r.Client.CriticalStack(cause, trace, m) - case hasTrace && level == logrus.PanicLevel: - _, err = r.Client.CriticalStack(cause, trace, m) - case hasTrace && level == logrus.ErrorLevel: - _, err = r.Client.ErrorStack(cause, trace, m) - case hasTrace && level == logrus.WarnLevel: - _, err = r.Client.WarningStack(cause, trace, m) - case level == logrus.FatalLevel || level == logrus.PanicLevel: - _, err = r.Client.Critical(cause, m) - case level == logrus.ErrorLevel: - _, err = r.Client.Error(cause, m) - case level == logrus.WarnLevel: - _, err = r.Client.Warning(cause, m) - case level == logrus.InfoLevel: - _, err = r.Client.Info(entry.Message, m) - case level == logrus.DebugLevel: - _, err = r.Client.Debug(entry.Message, m) - } - return err -} - -// convertFields converts from log.Fields to map[string]string so that we can -// report extra fields to Rollbar -func convertFields(fields logrus.Fields) map[string]string { - m := make(map[string]string) - for k, v := range fields { - switch t := v.(type) { - case time.Time: - m[k] = t.Format(time.RFC3339) - default: - if s, ok := v.(fmt.Stringer); ok { - m[k] = s.String() - } else { - m[k] = fmt.Sprintf("%+v", t) - } - } - } - - return m -} - -// extractError attempts to extract an error from a well known field, err or error -func extractError(entry *logrus.Entry) ([]uintptr, error) { - var trace []uintptr - fields := entry.Data - - type stackTracer interface { - StackTrace() errors.StackTrace - } - - for _, f := range wellKnownErrorFields { - e, ok := fields[f] - if !ok { - continue - } - err, ok := e.(error) - if !ok { - continue - } - - cause := errors.Cause(err) - tracer, ok := err.(stackTracer) - if ok { - return copyStackTrace(tracer.StackTrace()), cause - } - return trace, cause - } - - // when no error found, default to the logged message. - return trace, fmt.Errorf(entry.Message) -} - -func copyStackTrace(trace errors.StackTrace) (out []uintptr) { - for _, frame := range trace { - out = append(out, uintptr(frame)) - } - return -} diff --git a/vendor/github.com/jesseduffield/roll/LICENSE b/vendor/github.com/jesseduffield/roll/LICENSE new file mode 100644 index 000000000..1235e06b5 --- /dev/null +++ b/vendor/github.com/jesseduffield/roll/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2016 Stovepipe Studios + +MIT License + +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/github.com/jesseduffield/roll/client.go b/vendor/github.com/jesseduffield/roll/client.go new file mode 100644 index 000000000..284a3a883 --- /dev/null +++ b/vendor/github.com/jesseduffield/roll/client.go @@ -0,0 +1,242 @@ +package roll + +import ( + "bytes" + "encoding/json" + "fmt" + "hash/adler32" + "io" + "io/ioutil" + "net/http" + "os" + "reflect" + "runtime" + "strings" + "time" +) + +const ( + // By default, all Rollbar API requests are sent to this endpoint. + endpoint = "https://api.rollbar.com/api/1/item/" + + // Identify this Rollbar client library to the Rollbar API. + clientName = "go-roll" + clientVersion = "0.2.0" + clientLanguage = "go" +) + +var ( + // Endpoint is the default HTTP(S) endpoint that all Rollbar API requests + // will be sent to. By default, this is Rollbar's "Items" API endpoint. If + // this is blank, no items will be sent to Rollbar. + Endpoint = endpoint + + // Rollbar access token for the global client. If this is blank, no items + // will be sent to Rollbar. + Token = "" + + // Environment for all items reported with the global client. + Environment = "development" +) + +type rollbarSuccess struct { + Result map[string]string `json:"result"` +} + +// Client reports items to a single Rollbar project. +type Client interface { + Critical(err error, custom map[string]string) (uuid string, e error) + CriticalStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) + Error(err error, custom map[string]string) (uuid string, e error) + ErrorStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) + Warning(err error, custom map[string]string) (uuid string, e error) + WarningStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) + Info(msg string, custom map[string]string) (uuid string, e error) + Debug(msg string, custom map[string]string) (uuid string, e error) +} + +type rollbarClient struct { + token string + env string +} + +// New creates a new Rollbar client that reports items to the given project +// token and with the given environment (eg. "production", "development", etc). +func New(token, env string) Client { + return &rollbarClient{token, env} +} + +func Critical(err error, custom map[string]string) (uuid string, e error) { + return CriticalStack(err, getCallers(2), custom) +} + +func CriticalStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { + return New(Token, Environment).CriticalStack(err, ptrs, custom) +} + +func Error(err error, custom map[string]string) (uuid string, e error) { + return ErrorStack(err, getCallers(2), custom) +} + +func ErrorStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { + return New(Token, Environment).ErrorStack(err, ptrs, custom) +} + +func Warning(err error, custom map[string]string) (uuid string, e error) { + return WarningStack(err, getCallers(2), custom) +} + +func WarningStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { + return New(Token, Environment).WarningStack(err, ptrs, custom) +} + +func Info(msg string, custom map[string]string) (uuid string, e error) { + return New(Token, Environment).Info(msg, custom) +} + +func Debug(msg string, custom map[string]string) (uuid string, e error) { + return New(Token, Environment).Debug(msg, custom) +} + +func (c *rollbarClient) Critical(err error, custom map[string]string) (uuid string, e error) { + return c.CriticalStack(err, getCallers(2), custom) +} + +func (c *rollbarClient) CriticalStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { + item := c.buildTraceItem("critical", err, callers, custom) + return c.send(item) +} + +func (c *rollbarClient) Error(err error, custom map[string]string) (uuid string, e error) { + return c.ErrorStack(err, getCallers(2), custom) +} + +func (c *rollbarClient) ErrorStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { + item := c.buildTraceItem("error", err, callers, custom) + return c.send(item) +} + +func (c *rollbarClient) Warning(err error, custom map[string]string) (uuid string, e error) { + return c.WarningStack(err, getCallers(2), custom) +} + +func (c *rollbarClient) WarningStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { + item := c.buildTraceItem("warning", err, callers, custom) + return c.send(item) +} + +func (c *rollbarClient) Info(msg string, custom map[string]string) (uuid string, e error) { + item := c.buildMessageItem("info", msg, custom) + return c.send(item) +} + +func (c *rollbarClient) Debug(msg string, custom map[string]string) (uuid string, e error) { + item := c.buildMessageItem("debug", msg, custom) + return c.send(item) +} + +func (c *rollbarClient) buildTraceItem(level string, err error, callers []uintptr, custom map[string]string) (item map[string]interface{}) { + stack := buildRollbarFrames(callers) + item = c.buildItem(level, err.Error(), custom) + itemData := item["data"].(map[string]interface{}) + itemData["fingerprint"] = stack.fingerprint() + itemData["body"] = map[string]interface{}{ + "trace": map[string]interface{}{ + "frames": stack, + "exception": map[string]interface{}{ + "class": errorClass(err), + "message": err.Error(), + }, + }, + } + + return item +} + +func (c *rollbarClient) buildMessageItem(level string, msg string, custom map[string]string) (item map[string]interface{}) { + item = c.buildItem(level, msg, custom) + itemData := item["data"].(map[string]interface{}) + itemData["body"] = map[string]interface{}{ + "message": map[string]interface{}{ + "body": msg, + }, + } + + return item +} + +func (c *rollbarClient) buildItem(level, title string, custom map[string]string) map[string]interface{} { + hostname, _ := os.Hostname() + + return map[string]interface{}{ + "access_token": c.token, + "data": map[string]interface{}{ + "environment": c.env, + "title": title, + "level": level, + "timestamp": time.Now().Unix(), + "platform": runtime.GOOS, + "language": clientLanguage, + "server": map[string]interface{}{ + "host": hostname, + }, + "notifier": map[string]interface{}{ + "name": clientName, + "version": clientVersion, + }, + "custom": custom, + }, + } +} + +// send reports the given item to Rollbar and returns either a UUID for the +// reported item or an error. +func (c *rollbarClient) send(item map[string]interface{}) (uuid string, err error) { + if len(c.token) == 0 || len(Endpoint) == 0 { + return "", nil + } + + jsonBody, err := json.Marshal(item) + if err != nil { + return "", err + } + + resp, err := http.Post(Endpoint, "application/json", bytes.NewReader(jsonBody)) + if err != nil { + // If something goes wrong it really does not matter + return "", nil + } + defer func() { + io.Copy(ioutil.Discard, resp.Body) + resp.Body.Close() + }() + + if resp.StatusCode != http.StatusOK { + // If something goes wrong it really does not matter + return "", nil + } + + // Extract UUID from JSON response + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", nil + } + success := rollbarSuccess{} + json.Unmarshal(body, &success) + + return success.Result["uuid"], nil +} + +// errorClass returns a class name for an error (eg. "ErrUnexpectedEOF"). For +// string errors, it returns an Adler-32 checksum of the error string. +func errorClass(err error) string { + class := reflect.TypeOf(err).String() + if class == "" { + return "panic" + } else if class == "*errors.errorString" { + checksum := adler32.Checksum([]byte(err.Error())) + return fmt.Sprintf("{%x}", checksum) + } else { + return strings.TrimPrefix(class, "*") + } +} diff --git a/vendor/github.com/jesseduffield/roll/stack.go b/vendor/github.com/jesseduffield/roll/stack.go new file mode 100644 index 000000000..c50425491 --- /dev/null +++ b/vendor/github.com/jesseduffield/roll/stack.go @@ -0,0 +1,98 @@ +package roll + +import ( + "fmt" + "hash/crc32" + "os" + "runtime" + "strings" +) + +var ( + knownFilePathPatterns = []string{ + "github.com/", + "code.google.com/", + "bitbucket.org/", + "launchpad.net/", + "gopkg.in/", + } +) + +func getCallers(skip int) (pc []uintptr) { + pc = make([]uintptr, 1000) + i := runtime.Callers(skip+1, pc) + return pc[0:i] +} + +// -- rollbarFrames + +type rollbarFrame struct { + Filename string `json:"filename"` + Method string `json:"method"` + Line int `json:"lineno"` +} + +type rollbarFrames []rollbarFrame + +// buildRollbarFrames takes a slice of function pointers and returns a Rollbar +// API payload containing the filename, method name, and line number of each +// function. +func buildRollbarFrames(callers []uintptr) (frames rollbarFrames) { + frames = rollbarFrames{} + + // 2016-08-24 - runtime.CallersFrames was added in Go 1.7, which should + // replace the following code when roll is able to require Go 1.7+. + for _, caller := range callers { + frame := rollbarFrame{ + Filename: "???", + Method: "???", + } + if fn := runtime.FuncForPC(caller); fn != nil { + name, line := fn.FileLine(caller) + frame.Filename = scrubFile(name) + frame.Line = line + frame.Method = scrubFunction(fn.Name()) + } + frames = append(frames, frame) + } + + return frames +} + +// fingerprint returns a checksum that uniquely identifies a stacktrace by the +// filename, method name, and line number of every frame in the stack. +func (f rollbarFrames) fingerprint() string { + hash := crc32.NewIEEE() + for _, frame := range f { + fmt.Fprintf(hash, "%s%s%d", frame.Filename, frame.Method, frame.Line) + } + return fmt.Sprintf("%x", hash.Sum32()) +} + +// -- Helpers + +// scrubFile removes unneeded information from the path of a source file. This +// makes them shorter in Rollbar UI as well as making them the same, regardless +// of the machine the code was compiled on. +// +// Example: +// /home/foo/go/src/github.com/stvp/roll/rollbar.go -> github.com/stvp/roll/rollbar.go +func scrubFile(s string) string { + var i int + for _, pattern := range knownFilePathPatterns { + i = strings.Index(s, pattern) + if i != -1 { + return s[i:] + } + } + return s +} + +// scrubFunction removes unneeded information from the full name of a function. +// +// Example: +// github.com/stvp/roll.getCallers -> roll.getCallers +func scrubFunction(name string) string { + end := strings.LastIndex(name, string(os.PathSeparator)) + return name[end+1 : len(name)] +} diff --git a/vendor/github.com/jesseduffield/rollrus/LICENSE b/vendor/github.com/jesseduffield/rollrus/LICENSE new file mode 100644 index 000000000..8d4a5174d --- /dev/null +++ b/vendor/github.com/jesseduffield/rollrus/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright © Heroku 2014 - 2015 + +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/github.com/jesseduffield/rollrus/rollrus.go b/vendor/github.com/jesseduffield/rollrus/rollrus.go new file mode 100644 index 000000000..2d32b4e56 --- /dev/null +++ b/vendor/github.com/jesseduffield/rollrus/rollrus.go @@ -0,0 +1,287 @@ +// Package rollrus combines github.com/jesseduffield/roll with github.com/sirupsen/logrus +// via logrus.Hook mechanism, so that whenever logrus' logger.Error/f(), +// logger.Fatal/f() or logger.Panic/f() are used the messages are +// intercepted and sent to rollbar. +// +// Using SetupLogging should suffice for basic use cases that use the logrus +// singleton logger. +// +// More custom uses are supported by creating a new Hook with NewHook and +// registering that hook with the logrus Logger of choice. +// +// The levels can be customized with the WithLevels OptionFunc. +// +// Specific errors can be ignored with the WithIgnoredErrors OptionFunc. This is +// useful for ignoring errors such as context.Canceled. +// +// See the Examples in the tests for more usage. +package rollrus + +import ( + "fmt" + "os" + "time" + + "github.com/jesseduffield/roll" + "github.com/pkg/errors" + "github.com/sirupsen/logrus" +) + +var defaultTriggerLevels = []logrus.Level{ + logrus.ErrorLevel, + logrus.FatalLevel, + logrus.PanicLevel, +} + +// Hook is a wrapper for the rollbar Client and is usable as a logrus.Hook. +type Hook struct { + roll.Client + triggers []logrus.Level + ignoredErrors []error + ignoreErrorFunc func(error) bool + ignoreFunc func(error, map[string]string) bool + + // only used for tests to verify whether or not a report happened. + reported bool +} + +// OptionFunc that can be passed to NewHook. +type OptionFunc func(*Hook) + +// wellKnownErrorFields are the names of the fields to be checked for values of +// type `error`, in priority order. +var wellKnownErrorFields = []string{ + logrus.ErrorKey, "err", +} + +// WithLevels is an OptionFunc that customizes the log.Levels the hook will +// report on. +func WithLevels(levels ...logrus.Level) OptionFunc { + return func(h *Hook) { + h.triggers = levels + } +} + +// WithMinLevel is an OptionFunc that customizes the log.Levels the hook will +// report on by selecting all levels more severe than the one provided. +func WithMinLevel(level logrus.Level) OptionFunc { + var levels []logrus.Level + for _, l := range logrus.AllLevels { + if l <= level { + levels = append(levels, l) + } + } + + return func(h *Hook) { + h.triggers = levels + } +} + +// WithIgnoredErrors is an OptionFunc that whitelists certain errors to prevent +// them from firing. See https://golang.org/ref/spec#Comparison_operators +func WithIgnoredErrors(errors ...error) OptionFunc { + return func(h *Hook) { + h.ignoredErrors = append(h.ignoredErrors, errors...) + } +} + +// WithIgnoreErrorFunc is an OptionFunc that receives the error that is about +// to be logged and returns true/false if it wants to fire a rollbar alert for. +func WithIgnoreErrorFunc(fn func(error) bool) OptionFunc { + return func(h *Hook) { + h.ignoreErrorFunc = fn + } +} + +// WithIgnoreFunc is an OptionFunc that receives the error and custom fields that are about +// to be logged and returns true/false if it wants to fire a rollbar alert for. +func WithIgnoreFunc(fn func(err error, fields map[string]string) bool) OptionFunc { + return func(h *Hook) { + h.ignoreFunc = fn + } +} + +// NewHook creates a hook that is intended for use with your own logrus.Logger +// instance. Uses the defualt report levels defined in wellKnownErrorFields. +func NewHook(token string, env string, opts ...OptionFunc) *Hook { + h := NewHookForLevels(token, env, defaultTriggerLevels) + + for _, o := range opts { + o(h) + } + + return h +} + +// NewHookForLevels provided by the caller. Otherwise works like NewHook. +func NewHookForLevels(token string, env string, levels []logrus.Level) *Hook { + return &Hook{ + Client: roll.New(token, env), + triggers: levels, + ignoredErrors: make([]error, 0), + ignoreErrorFunc: func(error) bool { return false }, + ignoreFunc: func(error, map[string]string) bool { return false }, + } +} + +// SetupLogging for use on Heroku. If token is not an empty string a rollbar +// hook is added with the environment set to env. The log formatter is set to a +// TextFormatter with timestamps disabled. +func SetupLogging(token, env string) { + setupLogging(token, env, defaultTriggerLevels) +} + +// SetupLoggingForLevels works like SetupLogging, but allows you to +// set the levels on which to trigger this hook. +func SetupLoggingForLevels(token, env string, levels []logrus.Level) { + setupLogging(token, env, levels) +} + +func setupLogging(token, env string, levels []logrus.Level) { + logrus.SetFormatter(&logrus.TextFormatter{DisableTimestamp: true}) + + if token != "" { + logrus.AddHook(NewHookForLevels(token, env, levels)) + } +} + +// ReportPanic attempts to report the panic to rollbar using the provided +// client and then re-panic. If it can't report the panic it will print an +// error to stderr. +func (r *Hook) ReportPanic() { + if p := recover(); p != nil { + if _, err := r.Client.Critical(fmt.Errorf("panic: %q", p), nil); err != nil { + fmt.Fprintf(os.Stderr, "reporting_panic=false err=%q\n", err) + } + panic(p) + } +} + +// ReportPanic attempts to report the panic to rollbar if the token is set +func ReportPanic(token, env string) { + if token != "" { + h := &Hook{Client: roll.New(token, env)} + h.ReportPanic() + } +} + +// Levels returns the logrus log.Levels that this hook handles +func (r *Hook) Levels() []logrus.Level { + if r.triggers == nil { + return defaultTriggerLevels + } + return r.triggers +} + +// Fire the hook. This is called by Logrus for entries that match the levels +// returned by Levels(). +func (r *Hook) Fire(entry *logrus.Entry) error { + trace, cause := extractError(entry) + for _, ie := range r.ignoredErrors { + if ie == cause { + return nil + } + } + + if r.ignoreErrorFunc(cause) { + return nil + } + + m := convertFields(entry.Data) + if _, exists := m["time"]; !exists { + m["time"] = entry.Time.Format(time.RFC3339) + } + + if r.ignoreFunc(cause, m) { + return nil + } + + return r.report(entry, cause, m, trace) +} + +func (r *Hook) report(entry *logrus.Entry, cause error, m map[string]string, trace []uintptr) (err error) { + hasTrace := len(trace) > 0 + level := entry.Level + + r.reported = true + + switch { + case hasTrace && level == logrus.FatalLevel: + _, err = r.Client.CriticalStack(cause, trace, m) + case hasTrace && level == logrus.PanicLevel: + _, err = r.Client.CriticalStack(cause, trace, m) + case hasTrace && level == logrus.ErrorLevel: + _, err = r.Client.ErrorStack(cause, trace, m) + case hasTrace && level == logrus.WarnLevel: + _, err = r.Client.WarningStack(cause, trace, m) + case level == logrus.FatalLevel || level == logrus.PanicLevel: + _, err = r.Client.Critical(cause, m) + case level == logrus.ErrorLevel: + _, err = r.Client.Error(cause, m) + case level == logrus.WarnLevel: + _, err = r.Client.Warning(cause, m) + case level == logrus.InfoLevel: + _, err = r.Client.Info(entry.Message, m) + case level == logrus.DebugLevel: + _, err = r.Client.Debug(entry.Message, m) + } + return err +} + +// convertFields converts from log.Fields to map[string]string so that we can +// report extra fields to Rollbar +func convertFields(fields logrus.Fields) map[string]string { + m := make(map[string]string) + for k, v := range fields { + switch t := v.(type) { + case time.Time: + m[k] = t.Format(time.RFC3339) + default: + if s, ok := v.(fmt.Stringer); ok { + m[k] = s.String() + } else { + m[k] = fmt.Sprintf("%+v", t) + } + } + } + + return m +} + +// extractError attempts to extract an error from a well known field, err or error +func extractError(entry *logrus.Entry) ([]uintptr, error) { + var trace []uintptr + fields := entry.Data + + type stackTracer interface { + StackTrace() errors.StackTrace + } + + for _, f := range wellKnownErrorFields { + e, ok := fields[f] + if !ok { + continue + } + err, ok := e.(error) + if !ok { + continue + } + + cause := errors.Cause(err) + tracer, ok := err.(stackTracer) + if ok { + return copyStackTrace(tracer.StackTrace()), cause + } + return trace, cause + } + + // when no error found, default to the logged message. + return trace, fmt.Errorf(entry.Message) +} + +func copyStackTrace(trace errors.StackTrace) (out []uintptr) { + for _, frame := range trace { + out = append(out, uintptr(frame)) + } + return +} diff --git a/vendor/github.com/stvp/roll/LICENSE b/vendor/github.com/stvp/roll/LICENSE deleted file mode 100644 index 1235e06b5..000000000 --- a/vendor/github.com/stvp/roll/LICENSE +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2016 Stovepipe Studios - -MIT License - -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/github.com/stvp/roll/client.go b/vendor/github.com/stvp/roll/client.go deleted file mode 100644 index 687343f2a..000000000 --- a/vendor/github.com/stvp/roll/client.go +++ /dev/null @@ -1,240 +0,0 @@ -package roll - -import ( - "bytes" - "encoding/json" - "fmt" - "hash/adler32" - "io" - "io/ioutil" - "net/http" - "os" - "reflect" - "runtime" - "strings" - "time" -) - -const ( - // By default, all Rollbar API requests are sent to this endpoint. - endpoint = "https://api.rollbar.com/api/1/item/" - - // Identify this Rollbar client library to the Rollbar API. - clientName = "go-roll" - clientVersion = "0.2.0" - clientLanguage = "go" -) - -var ( - // Endpoint is the default HTTP(S) endpoint that all Rollbar API requests - // will be sent to. By default, this is Rollbar's "Items" API endpoint. If - // this is blank, no items will be sent to Rollbar. - Endpoint = endpoint - - // Rollbar access token for the global client. If this is blank, no items - // will be sent to Rollbar. - Token = "" - - // Environment for all items reported with the global client. - Environment = "development" -) - -type rollbarSuccess struct { - Result map[string]string `json:"result"` -} - -// Client reports items to a single Rollbar project. -type Client interface { - Critical(err error, custom map[string]string) (uuid string, e error) - CriticalStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) - Error(err error, custom map[string]string) (uuid string, e error) - ErrorStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) - Warning(err error, custom map[string]string) (uuid string, e error) - WarningStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) - Info(msg string, custom map[string]string) (uuid string, e error) - Debug(msg string, custom map[string]string) (uuid string, e error) -} - -type rollbarClient struct { - token string - env string -} - -// New creates a new Rollbar client that reports items to the given project -// token and with the given environment (eg. "production", "development", etc). -func New(token, env string) Client { - return &rollbarClient{token, env} -} - -func Critical(err error, custom map[string]string) (uuid string, e error) { - return CriticalStack(err, getCallers(2), custom) -} - -func CriticalStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { - return New(Token, Environment).CriticalStack(err, ptrs, custom) -} - -func Error(err error, custom map[string]string) (uuid string, e error) { - return ErrorStack(err, getCallers(2), custom) -} - -func ErrorStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { - return New(Token, Environment).ErrorStack(err, ptrs, custom) -} - -func Warning(err error, custom map[string]string) (uuid string, e error) { - return WarningStack(err, getCallers(2), custom) -} - -func WarningStack(err error, ptrs []uintptr, custom map[string]string) (uuid string, e error) { - return New(Token, Environment).WarningStack(err, ptrs, custom) -} - -func Info(msg string, custom map[string]string) (uuid string, e error) { - return New(Token, Environment).Info(msg, custom) -} - -func Debug(msg string, custom map[string]string) (uuid string, e error) { - return New(Token, Environment).Debug(msg, custom) -} - -func (c *rollbarClient) Critical(err error, custom map[string]string) (uuid string, e error) { - return c.CriticalStack(err, getCallers(2), custom) -} - -func (c *rollbarClient) CriticalStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { - item := c.buildTraceItem("critical", err, callers, custom) - return c.send(item) -} - -func (c *rollbarClient) Error(err error, custom map[string]string) (uuid string, e error) { - return c.ErrorStack(err, getCallers(2), custom) -} - -func (c *rollbarClient) ErrorStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { - item := c.buildTraceItem("error", err, callers, custom) - return c.send(item) -} - -func (c *rollbarClient) Warning(err error, custom map[string]string) (uuid string, e error) { - return c.WarningStack(err, getCallers(2), custom) -} - -func (c *rollbarClient) WarningStack(err error, callers []uintptr, custom map[string]string) (uuid string, e error) { - item := c.buildTraceItem("warning", err, callers, custom) - return c.send(item) -} - -func (c *rollbarClient) Info(msg string, custom map[string]string) (uuid string, e error) { - item := c.buildMessageItem("info", msg, custom) - return c.send(item) -} - -func (c *rollbarClient) Debug(msg string, custom map[string]string) (uuid string, e error) { - item := c.buildMessageItem("debug", msg, custom) - return c.send(item) -} - -func (c *rollbarClient) buildTraceItem(level string, err error, callers []uintptr, custom map[string]string) (item map[string]interface{}) { - stack := buildRollbarFrames(callers) - item = c.buildItem(level, err.Error(), custom) - itemData := item["data"].(map[string]interface{}) - itemData["fingerprint"] = stack.fingerprint() - itemData["body"] = map[string]interface{}{ - "trace": map[string]interface{}{ - "frames": stack, - "exception": map[string]interface{}{ - "class": errorClass(err), - "message": err.Error(), - }, - }, - } - - return item -} - -func (c *rollbarClient) buildMessageItem(level string, msg string, custom map[string]string) (item map[string]interface{}) { - item = c.buildItem(level, msg, custom) - itemData := item["data"].(map[string]interface{}) - itemData["body"] = map[string]interface{}{ - "message": map[string]interface{}{ - "body": msg, - }, - } - - return item -} - -func (c *rollbarClient) buildItem(level, title string, custom map[string]string) map[string]interface{} { - hostname, _ := os.Hostname() - - return map[string]interface{}{ - "access_token": c.token, - "data": map[string]interface{}{ - "environment": c.env, - "title": title, - "level": level, - "timestamp": time.Now().Unix(), - "platform": runtime.GOOS, - "language": clientLanguage, - "server": map[string]interface{}{ - "host": hostname, - }, - "notifier": map[string]interface{}{ - "name": clientName, - "version": clientVersion, - }, - "custom": custom, - }, - } -} - -// send reports the given item to Rollbar and returns either a UUID for the -// reported item or an error. -func (c *rollbarClient) send(item map[string]interface{}) (uuid string, err error) { - if len(c.token) == 0 || len(Endpoint) == 0 { - return "", nil - } - - jsonBody, err := json.Marshal(item) - if err != nil { - return "", err - } - - resp, err := http.Post(Endpoint, "application/json", bytes.NewReader(jsonBody)) - if err != nil { - return "", err - } - defer func() { - io.Copy(ioutil.Discard, resp.Body) - resp.Body.Close() - }() - - if resp.StatusCode != http.StatusOK { - return "", fmt.Errorf("Rollbar returned %s", resp.Status) - } - - // Extract UUID from JSON response - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return "", nil - } - success := rollbarSuccess{} - json.Unmarshal(body, &success) - - return success.Result["uuid"], nil -} - -// errorClass returns a class name for an error (eg. "ErrUnexpectedEOF"). For -// string errors, it returns an Adler-32 checksum of the error string. -func errorClass(err error) string { - class := reflect.TypeOf(err).String() - if class == "" { - return "panic" - } else if class == "*errors.errorString" { - checksum := adler32.Checksum([]byte(err.Error())) - return fmt.Sprintf("{%x}", checksum) - } else { - return strings.TrimPrefix(class, "*") - } -} diff --git a/vendor/github.com/stvp/roll/stack.go b/vendor/github.com/stvp/roll/stack.go deleted file mode 100644 index c50425491..000000000 --- a/vendor/github.com/stvp/roll/stack.go +++ /dev/null @@ -1,98 +0,0 @@ -package roll - -import ( - "fmt" - "hash/crc32" - "os" - "runtime" - "strings" -) - -var ( - knownFilePathPatterns = []string{ - "github.com/", - "code.google.com/", - "bitbucket.org/", - "launchpad.net/", - "gopkg.in/", - } -) - -func getCallers(skip int) (pc []uintptr) { - pc = make([]uintptr, 1000) - i := runtime.Callers(skip+1, pc) - return pc[0:i] -} - -// -- rollbarFrames - -type rollbarFrame struct { - Filename string `json:"filename"` - Method string `json:"method"` - Line int `json:"lineno"` -} - -type rollbarFrames []rollbarFrame - -// buildRollbarFrames takes a slice of function pointers and returns a Rollbar -// API payload containing the filename, method name, and line number of each -// function. -func buildRollbarFrames(callers []uintptr) (frames rollbarFrames) { - frames = rollbarFrames{} - - // 2016-08-24 - runtime.CallersFrames was added in Go 1.7, which should - // replace the following code when roll is able to require Go 1.7+. - for _, caller := range callers { - frame := rollbarFrame{ - Filename: "???", - Method: "???", - } - if fn := runtime.FuncForPC(caller); fn != nil { - name, line := fn.FileLine(caller) - frame.Filename = scrubFile(name) - frame.Line = line - frame.Method = scrubFunction(fn.Name()) - } - frames = append(frames, frame) - } - - return frames -} - -// fingerprint returns a checksum that uniquely identifies a stacktrace by the -// filename, method name, and line number of every frame in the stack. -func (f rollbarFrames) fingerprint() string { - hash := crc32.NewIEEE() - for _, frame := range f { - fmt.Fprintf(hash, "%s%s%d", frame.Filename, frame.Method, frame.Line) - } - return fmt.Sprintf("%x", hash.Sum32()) -} - -// -- Helpers - -// scrubFile removes unneeded information from the path of a source file. This -// makes them shorter in Rollbar UI as well as making them the same, regardless -// of the machine the code was compiled on. -// -// Example: -// /home/foo/go/src/github.com/stvp/roll/rollbar.go -> github.com/stvp/roll/rollbar.go -func scrubFile(s string) string { - var i int - for _, pattern := range knownFilePathPatterns { - i = strings.Index(s, pattern) - if i != -1 { - return s[i:] - } - } - return s -} - -// scrubFunction removes unneeded information from the full name of a function. -// -// Example: -// github.com/stvp/roll.getCallers -> roll.getCallers -func scrubFunction(name string) string { - end := strings.LastIndex(name, string(os.PathSeparator)) - return name[end+1 : len(name)] -} -- cgit v1.2.3