Merge pull request #849 from BrianBland/ng-error-reporting
Adds bugsnag and newrelic metrics and error reporting
This commit is contained in:
commit
8fd47c1c18
3 changed files with 117 additions and 1 deletions
|
@ -11,6 +11,9 @@ import (
|
||||||
|
|
||||||
log "github.com/Sirupsen/logrus"
|
log "github.com/Sirupsen/logrus"
|
||||||
|
|
||||||
|
"github.com/bugsnag/bugsnag-go"
|
||||||
|
"github.com/yvasiyarov/gorelic"
|
||||||
|
|
||||||
"github.com/docker/docker-registry"
|
"github.com/docker/docker-registry"
|
||||||
"github.com/docker/docker-registry/configuration"
|
"github.com/docker/docker-registry/configuration"
|
||||||
_ "github.com/docker/docker-registry/storagedriver/filesystem"
|
_ "github.com/docker/docker-registry/storagedriver/filesystem"
|
||||||
|
@ -27,7 +30,8 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
app := registry.NewApp(*config)
|
app := registry.NewApp(*config)
|
||||||
handler := handlers.CombinedLoggingHandler(os.Stdout, app)
|
handler := configureReporting(app)
|
||||||
|
handler = handlers.CombinedLoggingHandler(os.Stdout, handler)
|
||||||
log.SetLevel(logLevel(config.Loglevel))
|
log.SetLevel(logLevel(config.Loglevel))
|
||||||
|
|
||||||
log.Infof("listening on %v", config.HTTP.Addr)
|
log.Infof("listening on %v", config.HTTP.Addr)
|
||||||
|
@ -82,3 +86,39 @@ func logLevel(level configuration.Loglevel) log.Level {
|
||||||
|
|
||||||
return l
|
return l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func configureReporting(app *registry.App) http.Handler {
|
||||||
|
var handler http.Handler = app
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
|
if app.Config.Reporting.NewRelic.LicenseKey != "" {
|
||||||
|
agent := gorelic.NewAgent()
|
||||||
|
agent.NewrelicLicense = app.Config.Reporting.NewRelic.LicenseKey
|
||||||
|
if app.Config.Reporting.NewRelic.Name != "" {
|
||||||
|
agent.NewrelicName = app.Config.Reporting.NewRelic.Name
|
||||||
|
}
|
||||||
|
agent.CollectHTTPStat = true
|
||||||
|
agent.Verbose = true
|
||||||
|
agent.Run()
|
||||||
|
|
||||||
|
handler = agent.WrapHTTPHandler(handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,9 @@ type Configuration struct {
|
||||||
// Storage is the configuration for the registry's storage driver
|
// Storage is the configuration for the registry's storage driver
|
||||||
Storage Storage `yaml:"storage"`
|
Storage Storage `yaml:"storage"`
|
||||||
|
|
||||||
|
// Reporting is the configuration for error reporting
|
||||||
|
Reporting Reporting `yaml:"reporting"`
|
||||||
|
|
||||||
// HTTP contains configuration parameters for the registry's http
|
// HTTP contains configuration parameters for the registry's http
|
||||||
// interface.
|
// interface.
|
||||||
HTTP struct {
|
HTTP struct {
|
||||||
|
@ -180,6 +183,33 @@ func (storage Storage) MarshalYAML() (interface{}, error) {
|
||||||
// Parameters defines a key-value parameters mapping
|
// Parameters defines a key-value parameters mapping
|
||||||
type Parameters map[string]string
|
type Parameters map[string]string
|
||||||
|
|
||||||
|
// Reporting defines error reporting methods.
|
||||||
|
type Reporting struct {
|
||||||
|
// Bugsnag configures error reporting for Bugsnag (bugsnag.com).
|
||||||
|
Bugsnag BugsnagReporting `yaml:"bugsnag"`
|
||||||
|
// NewRelic configures error reporting for NewRelic (newrelic.com)
|
||||||
|
NewRelic NewRelicReporting `yaml:"newrelic"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// BugsnagReporting configures error reporting for Bugsnag (bugsnag.com).
|
||||||
|
type BugsnagReporting struct {
|
||||||
|
// APIKey is the Bugsnag api key.
|
||||||
|
APIKey string `yaml:"apikey"`
|
||||||
|
// ReleaseStage tracks where the registry is deployed.
|
||||||
|
// Examples: production, staging, development
|
||||||
|
ReleaseStage string `yaml:"releasestage"`
|
||||||
|
// Endpoint is used for specifying an enterprise Bugsnag endpoint.
|
||||||
|
Endpoint string `yaml:"endpoint"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewRelicReporting configures error reporting for NewRelic (newrelic.com)
|
||||||
|
type NewRelicReporting struct {
|
||||||
|
// LicenseKey is the NewRelic user license key
|
||||||
|
LicenseKey string `yaml:"licensekey"`
|
||||||
|
// AppName is the component name of the registry in NewRelic
|
||||||
|
Name string `yaml:"name"`
|
||||||
|
}
|
||||||
|
|
||||||
// Parse parses an input configuration yaml document into a Configuration struct
|
// Parse parses an input configuration yaml document into a Configuration struct
|
||||||
// This should generally be capable of handling old configuration format versions
|
// This should generally be capable of handling old configuration format versions
|
||||||
//
|
//
|
||||||
|
@ -264,6 +294,23 @@ func parseV0_1Registry(in []byte) (*Configuration, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if bugsnagAPIKey, ok := envMap["REGISTRY_REPORTING_BUGSNAG_APIKEY"]; ok {
|
||||||
|
config.Reporting.Bugsnag.APIKey = bugsnagAPIKey
|
||||||
|
}
|
||||||
|
if bugsnagReleaseStage, ok := envMap["REGISTRY_REPORTING_BUGSNAG_RELEASESTAGE"]; ok {
|
||||||
|
config.Reporting.Bugsnag.ReleaseStage = bugsnagReleaseStage
|
||||||
|
}
|
||||||
|
if bugsnagEndpoint, ok := envMap["REGISTRY_REPORTING_BUGSNAG_ENDPOINT"]; ok {
|
||||||
|
config.Reporting.Bugsnag.Endpoint = bugsnagEndpoint
|
||||||
|
}
|
||||||
|
|
||||||
|
if newRelicLicenseKey, ok := envMap["REGISTRY_REPORTING_NEWRELIC_LICENSEKEY"]; ok {
|
||||||
|
config.Reporting.NewRelic.LicenseKey = newRelicLicenseKey
|
||||||
|
}
|
||||||
|
if newRelicName, ok := envMap["REGISTRY_REPORTING_NEWRELIC_NAME"]; ok {
|
||||||
|
config.Reporting.NewRelic.Name = newRelicName
|
||||||
|
}
|
||||||
|
|
||||||
return (*Configuration)(&config), nil
|
return (*Configuration)(&config), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,11 @@ var configStruct = Configuration{
|
||||||
"port": "",
|
"port": "",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
Reporting: Reporting{
|
||||||
|
Bugsnag: BugsnagReporting{
|
||||||
|
APIKey: "BugsnagApiKey",
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// configYamlV0_1 is a Version 0.1 yaml document representing configStruct
|
// configYamlV0_1 is a Version 0.1 yaml document representing configStruct
|
||||||
|
@ -46,6 +51,9 @@ storage:
|
||||||
secretkey: SUPERSECRET
|
secretkey: SUPERSECRET
|
||||||
host: ~
|
host: ~
|
||||||
port: ~
|
port: ~
|
||||||
|
reporting:
|
||||||
|
bugsnag:
|
||||||
|
apikey: BugsnagApiKey
|
||||||
`
|
`
|
||||||
|
|
||||||
// inmemoryConfigYamlV0_1 is a Version 0.1 yaml document specifying an inmemory storage driver with
|
// inmemoryConfigYamlV0_1 is a Version 0.1 yaml document specifying an inmemory storage driver with
|
||||||
|
@ -88,6 +96,7 @@ func (suite *ConfigSuite) TestParseSimple(c *C) {
|
||||||
// parsed into a Configuration struct with no storage parameters
|
// parsed into a Configuration struct with no storage parameters
|
||||||
func (suite *ConfigSuite) TestParseInmemory(c *C) {
|
func (suite *ConfigSuite) TestParseInmemory(c *C) {
|
||||||
suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}}
|
suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}}
|
||||||
|
suite.expectedConfig.Reporting = Reporting{}
|
||||||
|
|
||||||
config, err := Parse(bytes.NewReader([]byte(inmemoryConfigYamlV0_1)))
|
config, err := Parse(bytes.NewReader([]byte(inmemoryConfigYamlV0_1)))
|
||||||
c.Assert(err, IsNil)
|
c.Assert(err, IsNil)
|
||||||
|
@ -171,6 +180,22 @@ func (suite *ConfigSuite) TestParseWithDifferentEnvLoglevel(c *C) {
|
||||||
c.Assert(config, DeepEquals, suite.expectedConfig)
|
c.Assert(config, DeepEquals, suite.expectedConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (suite *ConfigSuite) TestParseWithDifferentEnvReporting(c *C) {
|
||||||
|
suite.expectedConfig.Reporting.Bugsnag.APIKey = "anotherBugsnagApiKey"
|
||||||
|
suite.expectedConfig.Reporting.Bugsnag.Endpoint = "localhost:8080"
|
||||||
|
suite.expectedConfig.Reporting.NewRelic.LicenseKey = "NewRelicLicenseKey"
|
||||||
|
suite.expectedConfig.Reporting.NewRelic.Name = "some NewRelic NAME"
|
||||||
|
|
||||||
|
os.Setenv("REGISTRY_REPORTING_BUGSNAG_APIKEY", "anotherBugsnagApiKey")
|
||||||
|
os.Setenv("REGISTRY_REPORTING_BUGSNAG_ENDPOINT", "localhost:8080")
|
||||||
|
os.Setenv("REGISTRY_REPORTING_NEWRELIC_LICENSEKEY", "NewRelicLicenseKey")
|
||||||
|
os.Setenv("REGISTRY_REPORTING_NEWRELIC_NAME", "some NewRelic NAME")
|
||||||
|
|
||||||
|
config, err := Parse(bytes.NewReader([]byte(configYamlV0_1)))
|
||||||
|
c.Assert(err, IsNil)
|
||||||
|
c.Assert(config, DeepEquals, suite.expectedConfig)
|
||||||
|
}
|
||||||
|
|
||||||
// TestParseInvalidVersion validates that the parser will fail to parse a newer configuration
|
// TestParseInvalidVersion validates that the parser will fail to parse a newer configuration
|
||||||
// version than the CurrentVersion
|
// version than the CurrentVersion
|
||||||
func (suite *ConfigSuite) TestParseInvalidVersion(c *C) {
|
func (suite *ConfigSuite) TestParseInvalidVersion(c *C) {
|
||||||
|
@ -190,6 +215,10 @@ func copyConfig(config Configuration) *Configuration {
|
||||||
for k, v := range config.Storage.Parameters() {
|
for k, v := range config.Storage.Parameters() {
|
||||||
configCopy.Storage.setParameter(k, v)
|
configCopy.Storage.setParameter(k, v)
|
||||||
}
|
}
|
||||||
|
configCopy.Reporting = Reporting{
|
||||||
|
Bugsnag: BugsnagReporting{config.Reporting.Bugsnag.APIKey, config.Reporting.Bugsnag.ReleaseStage, config.Reporting.Bugsnag.Endpoint},
|
||||||
|
NewRelic: NewRelicReporting{config.Reporting.NewRelic.LicenseKey, config.Reporting.NewRelic.Name},
|
||||||
|
}
|
||||||
|
|
||||||
return configCopy
|
return configCopy
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue