summaryrefslogtreecommitdiffstats
path: root/vendor
diff options
context:
space:
mode:
authorJesse Duffield <jessedduffield@gmail.com>2018-08-27 20:35:55 +1000
committerJesse Duffield <jessedduffield@gmail.com>2018-08-27 20:35:55 +1000
commit23a9f41d9db3e449ec79e4fde46c54b3c5611368 (patch)
tree969b5f9348c5f8e1e4e824a050695f6a604670f0 /vendor
parent1901901d243f4a4f9c90ce10b61aecc36b83374b (diff)
parenta1c6adab59e742adc6d4207fecd41c7fd18ceeca (diff)
Merge branch 'feature/anonymous-reporting'
Diffstat (limited to 'vendor')
-rw-r--r--vendor/github.com/heroku/rollrus/LICENSE22
-rw-r--r--vendor/github.com/heroku/rollrus/rollrus.go287
-rw-r--r--vendor/github.com/pkg/errors/LICENSE23
-rw-r--r--vendor/github.com/pkg/errors/errors.go269
-rw-r--r--vendor/github.com/pkg/errors/stack.go178
-rw-r--r--vendor/github.com/stvp/roll/LICENSE22
-rw-r--r--vendor/github.com/stvp/roll/client.go240
-rw-r--r--vendor/github.com/stvp/roll/stack.go98
8 files changed, 1139 insertions, 0 deletions
diff --git a/vendor/github.com/heroku/rollrus/LICENSE b/vendor/github.com/heroku/rollrus/LICENSE
new file mode 100644
index 000000000..8d4a5174d
--- /dev/null
+++ b/vendor/github.com/heroku/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/heroku/rollrus/rollrus.go b/vendor/github.com/heroku/rollrus/rollrus.go
new file mode 100644
index 000000000..50dd225da
--- /dev/null
+++ b/vendor/github.com/heroku/rollrus/rollrus.go
@@ -0,0 +1,287 @@
+// 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/pkg/errors/LICENSE b/vendor/github.com/pkg/errors/LICENSE
new file mode 100644
index 000000000..835ba3e75
--- /dev/null
+++ b/vendor/github.com/pkg/errors/LICENSE
@@ -0,0 +1,23 @@
+Copyright (c) 2015, Dave Cheney <dave@cheney.net>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/vendor/github.com/pkg/errors/errors.go b/vendor/github.com/pkg/errors/errors.go
new file mode 100644
index 000000000..842ee8045
--- /dev/null
+++ b/vendor/github.com/pkg/errors/errors.go
@@ -0,0 +1,269 @@
+// Package errors provides simple error handling primitives.
+//
+// The traditional error handling idiom in Go is roughly akin to
+//
+// if err != nil {
+// return err
+// }
+//
+// which applied recursively up the call stack results in error reports
+// without context or debugging information. The errors package allows
+// programmers to add context to the failure path in their code in a way
+// that does not destroy the original value of the error.
+//
+// Adding context to an error
+//
+// The errors.Wrap function returns a new error that adds context to the
+// original error by recording a stack trace at the point Wrap is called,
+// and the supplied message. For example
+//
+// _, err := ioutil.ReadAll(r)
+// if err != nil {
+// return errors.Wrap(err, "read failed")
+// }
+//
+// If additional control is required the errors.WithStack and errors.WithMessage
+// functions destructure errors.Wrap into its component operations of annotating
+// an error with a stack trace and an a message, respectively.
+//
+// Retrieving the cause of an error
+//
+// Using errors.Wrap constructs a stack of errors, adding context to the
+// preceding error. Depending on the nature of the error it may be necessary
+// to reverse the operation of errors.Wrap to retrieve the original error
+// for inspection. Any error value which implements this interface
+//
+// type causer interface {
+// Cause() error
+// }
+//
+// can be inspected by errors.Cause. errors.Cause will recursively retrieve
+// the topmost error which does not implement causer, which is assumed to be
+// the original cause. For example:
+//
+// switch err := errors.Cause(err).(type) {
+// case *MyError:
+// // handle specifically
+// default:
+// // unknown error
+// }
+//
+// causer interface is not exported by this package, but is considered a part
+// of stable public API.
+//
+// Formatted printing of errors
+//
+// All error values returned from this package implement fmt.Formatter and can
+// be formatted by the fmt package. The following verbs are supported
+//
+// %s print the error. If the error has a Cause it will be
+// printed recursively
+// %v see %s
+// %+v extended format. Each Frame of the error's StackTrace will
+// be printed in detail.
+//
+// Retrieving the stack trace of an error or wrapper
+//
+// New, Errorf, Wrap, and Wrapf record a stack trace at the point they are
+// invoked. This information can be retrieved with the following interface.
+//
+// type stackTracer interface {
+// StackTrace() errors.StackTrace
+// }
+//
+// Where errors.StackTrace is defined as
+//
+// type StackTrace []Frame
+//
+// The Frame type represents a call site in the stack trace. Frame supports
+// the fmt.Formatter interface that can be used for printing information about
+// the stack trace of this error. For example:
+//
+// if err, ok := err.(stackTracer); ok {
+// for _, f := range err.StackTrace() {
+// fmt.Printf("%+s:%d", f)
+// }
+// }
+//
+// stackTracer interface is not exported by this package, but is considered a part
+// of stable public API.
+//
+// See the documentation for Frame.Format for more details.
+package errors
+
+import (
+ "fmt"
+ "io"
+)
+
+// New returns an error with the supplied message.
+// New also records the stack trace at the point it was called.
+func New(message string) error {
+ return &fundamental{
+ msg: message,
+ stack: callers(),
+ }
+}
+
+// Errorf formats according to a format specifier and returns the string
+// as a value that satisfies error.
+// Errorf also records the stack trace at the point it was called.
+func Errorf(format string, args ...interface{}) error {
+ return &fundamental{
+ msg: fmt.Sprintf(format, args...),
+ stack: callers(),
+ }
+}
+
+// fundamental is an error that has a message and a stack, but no caller.
+type fundamental struct {
+ msg string
+ *stack
+}
+
+func (f *fundamental) Error() string { return f.msg }
+
+func (f *fundamental) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ io.WriteString(s, f.msg)
+ f.stack.Format(s, verb)
+ return
+ }
+ fallthrough
+ case 's':
+ io.WriteString(s, f.msg)
+ case 'q':
+ fmt.Fprintf(s, "%q", f.msg)
+ }
+}
+
+// WithStack annotates err with a stack trace at the point WithStack was called.
+// If err is nil, WithStack returns nil.
+func WithStack(err error) error {
+ if err == nil {
+ return nil
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+type withStack struct {
+ error
+ *stack
+}
+
+func (w *withStack) Cause() error { return w.error }
+
+func (w *withStack) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ fmt.Fprintf(s, "%+v", w.Cause())
+ w.stack.Format(s, verb)
+ return
+ }
+ fallthrough
+ case 's':
+ io.WriteString(s, w.Error())
+ case 'q':
+ fmt.Fprintf(s, "%q", w.Error())
+ }
+}
+
+// Wrap returns an error annotating err with a stack trace
+// at the point Wrap is called, and the supplied message.
+// If err is nil, Wrap returns nil.
+func Wrap(err error, message string) error {
+ if err == nil {
+ return nil
+ }
+ err = &withMessage{
+ cause: err,
+ msg: message,
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+// Wrapf returns an error annotating err with a stack trace
+// at the point Wrapf is call, and the format specifier.
+// If err is nil, Wrapf returns nil.
+func Wrapf(err error, format string, args ...interface{}) error {
+ if err == nil {
+ return nil
+ }
+ err = &withMessage{
+ cause: err,
+ msg: fmt.Sprintf(format, args...),
+ }
+ return &withStack{
+ err,
+ callers(),
+ }
+}
+
+// WithMessage annotates err with a new message.
+// If err is nil, WithMessage returns nil.
+func WithMessage(err error, message string) error {
+ if err == nil {
+ return nil
+ }
+ return &withMessage{
+ cause: err,
+ msg: message,
+ }
+}
+
+type withMessage struct {
+ cause error
+ msg string
+}
+
+func (w *withMessage) Error() string { return w.msg + ": " + w.cause.Error() }
+func (w *withMessage) Cause() error { return w.cause }
+
+func (w *withMessage) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ if s.Flag('+') {
+ fmt.Fprintf(s, "%+v\n", w.Cause())
+ io.WriteString(s, w.msg)
+ return
+ }
+ fallthrough
+ case 's', 'q':
+ io.WriteString(s, w.Error())
+ }
+}
+
+// Cause returns the underlying cause of the error, if possible.
+// An error value has a cause if it implements the following
+// interface:
+//
+// type causer interface {
+// Cause() error
+// }
+//
+// If the error does not implement Cause, the original error will
+// be returned. If the error is nil, nil will be returned without further
+// investigation.
+func Cause(err error) error {
+ type causer interface {
+ Cause() error
+ }
+
+ for err != nil {
+ cause, ok := err.(causer)
+ if !ok {
+ break
+ }
+ err = cause.Cause()
+ }
+ return err
+}
diff --git a/vendor/github.com/pkg/errors/stack.go b/vendor/github.com/pkg/errors/stack.go
new file mode 100644
index 000000000..6b1f2891a
--- /dev/null
+++ b/vendor/github.com/pkg/errors/stack.go
@@ -0,0 +1,178 @@
+package errors
+
+import (
+ "fmt"
+ "io"
+ "path"
+ "runtime"
+ "strings"
+)
+
+// Frame represents a program counter inside a stack frame.
+type Frame uintptr
+
+// pc returns the program counter for this frame;
+// multiple frames may have the same PC value.
+func (f Frame) pc() uintptr { return uintptr(f) - 1 }
+
+// file returns the full path to the file that contains the
+// function for this Frame's pc.
+func (f Frame) file() string {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return "unknown"
+ }
+ file, _ := fn.FileLine(f.pc())
+ return file
+}
+
+// line returns the line number of source code of the
+// function for this Frame's pc.
+func (f Frame) line() int {
+ fn := runtime.FuncForPC(f.pc())
+ if fn == nil {
+ return 0
+ }
+ _, line := fn.FileLine(f.pc())
+ return line
+}
+
+// Format formats the frame according to the fmt.Formatter interface.
+//
+// %s source file
+// %d source line
+// %n function name
+// %v equivalent to %s:%d
+//
+// Format accepts flags that alter the printing of some verbs, as follows:
+//
+// %+s path of source file relative to the compile time GOPATH
+// %+v equivalent to %+s:%d
+func (f Frame) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 's':
+ switch {
+ case s.Flag('+'):
+ pc := f.pc()
+ fn := runtime.FuncForPC(pc)
+ if fn == nil {
+ io.WriteString(s, "unknown")
+ } else {
+ file, _ := fn.FileLine(pc)
+ fmt.Fprintf(s, "%s\n\t%s", fn.Name(), file)
+ }
+ default:
+ io.WriteString(s, path.Base(f.file()))
+ }
+ case 'd':
+ fmt.Fprintf(s, "%d", f.line())
+ case 'n':
+ name := runtime.FuncForPC(f.pc()).Name()
+ io.WriteString(s, funcname(name))
+ case 'v':
+ f.Format(s, 's')
+ io.WriteString(s, ":")
+ f.Format(s, 'd')
+ }
+}
+
+// StackTrace is stack of Frames from innermost (newest) to outermost (oldest).
+type StackTrace []Frame
+
+func (st StackTrace) Format(s fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ switch {
+ case s.Flag('+'):
+ for _, f := range st {
+ fmt.Fprintf(s, "\n%+v", f)
+ }
+ case s.Flag('#'):
+ fmt.Fprintf(s, "%#v", []Frame(st))
+ default:
+ fmt.Fprintf(s, "%v", []Frame(st))
+ }
+ case 's':
+ fmt.Fprintf(s, "%s", []Frame(st))
+ }
+}
+
+// stack represents a stack of program counters.
+type stack []uintptr
+
+func (s *stack) Format(st fmt.State, verb rune) {
+ switch verb {
+ case 'v':
+ switch {
+ case st.Flag('+'):
+ for _, pc := range *s {
+ f := Frame(pc)
+ fmt.Fprintf(st, "\n%+v", f)
+ }
+ }
+ }
+}
+
+func (s *stack) StackTrace() StackTrace {
+ f := make([]Frame, len(*s))
+ for i := 0; i < len(f); i++ {
+ f[i] = Frame((*s)[i])
+ }
+ return f
+}
+
+func callers() *stack {
+ const depth = 32
+ var pcs [depth]uintptr
+ n := runtime.Callers(3, pcs[:])
+ var st stack = pcs[0:n]
+ return &st
+}
+
+// funcname removes the path prefix component of a function's name reported by func.Name().
+func funcname(name string) string {
+ i := strings.LastIndex(name, "/")
+ name = name[i+1:]
+ i = strings.Index(name, ".")
+ return name[i+1:]
+}
+
+func trimGOPATH(name, file string) string {
+ // Here we want to get the source file path relative to the compile time
+ // GOPATH. As of Go 1.6.x there is no direct way to know the compiled
+ // GOPATH at runtime, but we can infer the number of path segments in the
+ // GOPATH. We note that fn.Name() returns the function name qualified by
+ // the import path, which does not include the GOPATH. Thus we can trim
+ // segments from the beginning of the file path until the number of path
+ // separators remaining is one more than the number of path separators in
+ // the function name. For example, given:
+ //
+ // GOPATH /home/user
+ // file /home/user/src/pkg/sub/file.go
+ // fn.Name() pkg/sub.Type.Method
+ //
+ // We want to produce:
+ //
+ // pkg/sub/file.go
+ //
+ // From this we can easily see that fn.Name() has one less path separator
+ // than our desired output. We count separators from the end of the file
+ // path until it finds two more than in the function name and then move
+ // one character forward to preserve the initial path segment without a
+ // leading separator.
+ const sep = "/"
+ goal := strings.Count(name, sep) + 2
+ i := len(file)
+ for n := 0; n < goal; n++ {
+ i = strings.LastIndex(file[:i], sep)
+ if i == -1 {
+ // not enough separators found, set i so that the slice expression
+ // below leaves file unmodified
+ i = -len(sep)
+ break
+ }
+ }
+ // get back to 0 or trim the leading separator
+ file = file[i+len(sep):]
+ return file
+}
diff --git a/vendor/github.com/stvp/roll/LICENSE b/vendor/github.com/stvp/roll/LICENSE
new file mode 100644
index 000000000..1235e06b5
--- /dev/null
+++ b/vendor/github.com/stvp/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/stvp/roll/client.go b/vendor/github.com/stvp/roll/client.go
new file mode 100644
index 000000000..687343f2a
--- /dev/null
+++ b/vendor/github.com/stvp/roll/client.go
@@ -0,0 +1,240 @@
+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,