add bugsnag logrus hook
Signed-off-by: Matt Tescher <matthew.tescher@docker.com>
This commit is contained in:
parent
93e082742a
commit
7c4d584e58
5 changed files with 156 additions and 13 deletions
|
@ -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
|
||||||
|
|
21
vendor/github.com/Shopify/logrus-bugsnag/LICENSE
generated
vendored
Normal file
21
vendor/github.com/Shopify/logrus-bugsnag/LICENSE
generated
vendored
Normal file
|
@ -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.
|
24
vendor/github.com/Shopify/logrus-bugsnag/README.md
generated
vendored
Normal file
24
vendor/github.com/Shopify/logrus-bugsnag/README.md
generated
vendored
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
## logrus-bugsnag
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/Shopify/logrus-bugsnag.svg)](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)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
81
vendor/github.com/Shopify/logrus-bugsnag/bugsnag.go
generated
vendored
Normal file
81
vendor/github.com/Shopify/logrus-bugsnag/bugsnag.go
generated
vendored
Normal file
|
@ -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 a new issue