commit
						dd36fd3622
					
				|  | @ -14,6 +14,7 @@ import ( | ||||||
| 
 | 
 | ||||||
| 	"rsc.io/letsencrypt" | 	"rsc.io/letsencrypt" | ||||||
| 
 | 
 | ||||||
|  | 	"github.com/Shopify/logrus-bugsnag" | ||||||
| 	logstash "github.com/bshuster-repo/logrus-logstash-hook" | 	logstash "github.com/bshuster-repo/logrus-logstash-hook" | ||||||
| 	"github.com/bugsnag/bugsnag-go" | 	"github.com/bugsnag/bugsnag-go" | ||||||
| 	"github.com/docker/distribution/configuration" | 	"github.com/docker/distribution/configuration" | ||||||
|  | @ -95,6 +96,8 @@ func NewRegistry(ctx context.Context, config *configuration.Configuration) (*Reg | ||||||
| 		return nil, fmt.Errorf("error configuring logger: %v", err) | 		return nil, fmt.Errorf("error configuring logger: %v", err) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	configureBugsnag(config) | ||||||
|  | 
 | ||||||
| 	// inject a logger into the uuid library. warns us if there is a problem
 | 	// inject a logger into the uuid library. warns us if there is a problem
 | ||||||
| 	// with uuid generation under low entropy.
 | 	// with uuid generation under low entropy.
 | ||||||
| 	uuid.Loggerf = dcontext.GetLogger(ctx).Warnf | 	uuid.Loggerf = dcontext.GetLogger(ctx).Warnf | ||||||
|  | @ -229,19 +232,6 @@ func configureReporting(app *handlers.App) http.Handler { | ||||||
| 	var handler http.Handler = app | 	var handler http.Handler = app | ||||||
| 
 | 
 | ||||||
| 	if app.Config.Reporting.Bugsnag.APIKey != "" { | 	if app.Config.Reporting.Bugsnag.APIKey != "" { | ||||||
| 		bugsnagConfig := bugsnag.Configuration{ |  | ||||||
| 			APIKey: app.Config.Reporting.Bugsnag.APIKey, |  | ||||||
| 			// TODO(brianbland): provide the registry version here
 |  | ||||||
| 			// AppVersion: "2.0",
 |  | ||||||
| 		} |  | ||||||
| 		if app.Config.Reporting.Bugsnag.ReleaseStage != "" { |  | ||||||
| 			bugsnagConfig.ReleaseStage = app.Config.Reporting.Bugsnag.ReleaseStage |  | ||||||
| 		} |  | ||||||
| 		if app.Config.Reporting.Bugsnag.Endpoint != "" { |  | ||||||
| 			bugsnagConfig.Endpoint = app.Config.Reporting.Bugsnag.Endpoint |  | ||||||
| 		} |  | ||||||
| 		bugsnag.Configure(bugsnagConfig) |  | ||||||
| 
 |  | ||||||
| 		handler = bugsnag.Handler(handler) | 		handler = bugsnag.Handler(handler) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -319,6 +309,32 @@ func logLevel(level configuration.Loglevel) log.Level { | ||||||
| 	return l | 	return l | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | // configureBugsnag configures bugsnag reporting, if enabled
 | ||||||
|  | func configureBugsnag(config *configuration.Configuration) { | ||||||
|  | 	if config.Reporting.Bugsnag.APIKey == "" { | ||||||
|  | 		return | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	bugsnagConfig := bugsnag.Configuration{ | ||||||
|  | 		APIKey: config.Reporting.Bugsnag.APIKey, | ||||||
|  | 	} | ||||||
|  | 	if config.Reporting.Bugsnag.ReleaseStage != "" { | ||||||
|  | 		bugsnagConfig.ReleaseStage = config.Reporting.Bugsnag.ReleaseStage | ||||||
|  | 	} | ||||||
|  | 	if config.Reporting.Bugsnag.Endpoint != "" { | ||||||
|  | 		bugsnagConfig.Endpoint = config.Reporting.Bugsnag.Endpoint | ||||||
|  | 	} | ||||||
|  | 	bugsnag.Configure(bugsnagConfig) | ||||||
|  | 
 | ||||||
|  | 	// configure logrus bugsnag hook
 | ||||||
|  | 	hook, err := logrus_bugsnag.NewBugsnagHook() | ||||||
|  | 	if err != nil { | ||||||
|  | 		log.Fatalln(err) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	log.AddHook(hook) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // panicHandler add an HTTP handler to web app. The handler recover the happening
 | // panicHandler add an HTTP handler to web app. The handler recover the happening
 | ||||||
| // panic. logrus.Panic transmits panic message to pre-config log hooks, which is
 | // panic. logrus.Panic transmits panic message to pre-config log hooks, which is
 | ||||||
| // defined in config.yml.
 | // defined in config.yml.
 | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ github.com/prometheus/client_golang c332b6f63c0658a65eca15c0e5247ded801cf564 | ||||||
| github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c | github.com/prometheus/client_model 99fa1f4be8e564e8a6b613da7fa6f46c9edafc6c | ||||||
| github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563 | github.com/prometheus/common 89604d197083d4781071d3c65855d24ecfb0a563 | ||||||
| github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd | github.com/prometheus/procfs cb4147076ac75738c9a7d279075a253c0cc5acbd | ||||||
|  | github.com/Shopify/logrus-bugsnag 577dee27f20dd8f1a529f82210094af593be12bd | ||||||
| github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064 | github.com/spf13/cobra 312092086bed4968099259622145a0c9ae280064 | ||||||
| github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842 | github.com/spf13/pflag 5644820622454e71517561946e3d94b9f9db6842 | ||||||
| github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985 | github.com/xenolf/lego a9d8cec0e6563575e5868a005359ac97911b5985 | ||||||
|  |  | ||||||
|  | @ -0,0 +1,21 @@ | ||||||
|  | The MIT License (MIT) | ||||||
|  | 
 | ||||||
|  | Copyright (c) 2016 Shopify | ||||||
|  | 
 | ||||||
|  | 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. | ||||||
|  | @ -0,0 +1,24 @@ | ||||||
|  | ## logrus-bugsnag | ||||||
|  | 
 | ||||||
|  | [](https://travis-ci.org/Shopify/logrus-bugsnag) | ||||||
|  | 
 | ||||||
|  | logrus-bugsnag is a hook that allows [Logrus](https://github.com/sirupsen/logrus) to interface with [Bugsnag](https://bugsnag.com). | ||||||
|  | 
 | ||||||
|  | #### Usage | ||||||
|  | 
 | ||||||
|  | ```go | ||||||
|  | import ( | ||||||
|  |   log "github.com/sirupsen/logrus" | ||||||
|  |   "github.com/Shopify/logrus-bugsnag" | ||||||
|  |   bugsnag "github.com/bugsnag/bugsnag-go" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | func init() { | ||||||
|  |   bugsnag.Configure(bugsnag.Configuration{ | ||||||
|  |     APIKey: apiKey, | ||||||
|  |   }) | ||||||
|  |   hook, err := logrus_bugsnag.NewBugsnagHook() | ||||||
|  |   logrus.StandardLogger().Hooks.Add(hook) | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | @ -0,0 +1,81 @@ | ||||||
|  | package logrus_bugsnag | ||||||
|  | 
 | ||||||
|  | import ( | ||||||
|  | 	"errors" | ||||||
|  | 
 | ||||||
|  | 	"github.com/sirupsen/logrus" | ||||||
|  | 	"github.com/bugsnag/bugsnag-go" | ||||||
|  | 	bugsnag_errors "github.com/bugsnag/bugsnag-go/errors" | ||||||
|  | ) | ||||||
|  | 
 | ||||||
|  | type bugsnagHook struct{} | ||||||
|  | 
 | ||||||
|  | // ErrBugsnagUnconfigured is returned if NewBugsnagHook is called before
 | ||||||
|  | // bugsnag.Configure. Bugsnag must be configured before the hook.
 | ||||||
|  | var ErrBugsnagUnconfigured = errors.New("bugsnag must be configured before installing this logrus hook") | ||||||
|  | 
 | ||||||
|  | // ErrBugsnagSendFailed indicates that the hook failed to submit an error to
 | ||||||
|  | // bugsnag. The error was successfully generated, but `bugsnag.Notify()`
 | ||||||
|  | // failed.
 | ||||||
|  | type ErrBugsnagSendFailed struct { | ||||||
|  | 	err error | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func (e ErrBugsnagSendFailed) Error() string { | ||||||
|  | 	return "failed to send error to Bugsnag: " + e.err.Error() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // NewBugsnagHook initializes a logrus hook which sends exceptions to an
 | ||||||
|  | // exception-tracking service compatible with the Bugsnag API. Before using
 | ||||||
|  | // this hook, you must call bugsnag.Configure(). The returned object should be
 | ||||||
|  | // registered with a log via `AddHook()`
 | ||||||
|  | //
 | ||||||
|  | // Entries that trigger an Error, Fatal or Panic should now include an "error"
 | ||||||
|  | // field to send to Bugsnag.
 | ||||||
|  | func NewBugsnagHook() (*bugsnagHook, error) { | ||||||
|  | 	if bugsnag.Config.APIKey == "" { | ||||||
|  | 		return nil, ErrBugsnagUnconfigured | ||||||
|  | 	} | ||||||
|  | 	return &bugsnagHook{}, nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // skipStackFrames skips logrus stack frames before logging to Bugsnag.
 | ||||||
|  | const skipStackFrames = 4 | ||||||
|  | 
 | ||||||
|  | // Fire forwards an error to Bugsnag. Given a logrus.Entry, it extracts the
 | ||||||
|  | // "error" field (or the Message if the error isn't present) and sends it off.
 | ||||||
|  | func (hook *bugsnagHook) Fire(entry *logrus.Entry) error { | ||||||
|  | 	var notifyErr error | ||||||
|  | 	err, ok := entry.Data["error"].(error) | ||||||
|  | 	if ok { | ||||||
|  | 		notifyErr = err | ||||||
|  | 	} else { | ||||||
|  | 		notifyErr = errors.New(entry.Message) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	metadata := bugsnag.MetaData{} | ||||||
|  | 	metadata["metadata"] = make(map[string]interface{}) | ||||||
|  | 	for key, val := range entry.Data { | ||||||
|  | 		if key != "error" { | ||||||
|  | 			metadata["metadata"][key] = val | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	errWithStack := bugsnag_errors.New(notifyErr, skipStackFrames) | ||||||
|  | 	bugsnagErr := bugsnag.Notify(errWithStack, metadata) | ||||||
|  | 	if bugsnagErr != nil { | ||||||
|  | 		return ErrBugsnagSendFailed{bugsnagErr} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return nil | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // Levels enumerates the log levels on which the error should be forwarded to
 | ||||||
|  | // bugsnag: everything at or above the "Error" level.
 | ||||||
|  | func (hook *bugsnagHook) Levels() []logrus.Level { | ||||||
|  | 	return []logrus.Level{ | ||||||
|  | 		logrus.ErrorLevel, | ||||||
|  | 		logrus.FatalLevel, | ||||||
|  | 		logrus.PanicLevel, | ||||||
|  | 	} | ||||||
|  | } | ||||||
		Loading…
	
		Reference in New Issue