Merge pull request #849 from BrianBland/ng-error-reporting
Adds bugsnag and newrelic metrics and error reportingmaster
						commit
						8fd47c1c18
					
				|  | @ -11,6 +11,9 @@ import ( | |||
| 
 | ||||
| 	log "github.com/Sirupsen/logrus" | ||||
| 
 | ||||
| 	"github.com/bugsnag/bugsnag-go" | ||||
| 	"github.com/yvasiyarov/gorelic" | ||||
| 
 | ||||
| 	"github.com/docker/docker-registry" | ||||
| 	"github.com/docker/docker-registry/configuration" | ||||
| 	_ "github.com/docker/docker-registry/storagedriver/filesystem" | ||||
|  | @ -27,7 +30,8 @@ func main() { | |||
| 	} | ||||
| 
 | ||||
| 	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.Infof("listening on %v", config.HTTP.Addr) | ||||
|  | @ -82,3 +86,39 @@ func logLevel(level configuration.Loglevel) log.Level { | |||
| 
 | ||||
| 	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 Storage `yaml:"storage"` | ||||
| 
 | ||||
| 	// Reporting is the configuration for error reporting
 | ||||
| 	Reporting Reporting `yaml:"reporting"` | ||||
| 
 | ||||
| 	// HTTP contains configuration parameters for the registry's http
 | ||||
| 	// interface.
 | ||||
| 	HTTP struct { | ||||
|  | @ -180,6 +183,33 @@ func (storage Storage) MarshalYAML() (interface{}, error) { | |||
| // Parameters defines a key-value parameters mapping
 | ||||
| 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
 | ||||
| // 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 | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -29,6 +29,11 @@ var configStruct = Configuration{ | |||
| 			"port":      "", | ||||
| 		}, | ||||
| 	}, | ||||
| 	Reporting: Reporting{ | ||||
| 		Bugsnag: BugsnagReporting{ | ||||
| 			APIKey: "BugsnagApiKey", | ||||
| 		}, | ||||
| 	}, | ||||
| } | ||||
| 
 | ||||
| // configYamlV0_1 is a Version 0.1 yaml document representing configStruct
 | ||||
|  | @ -46,6 +51,9 @@ storage: | |||
|     secretkey: SUPERSECRET | ||||
|     host: ~ | ||||
|     port: ~ | ||||
| reporting: | ||||
|   bugsnag: | ||||
|     apikey: BugsnagApiKey | ||||
| ` | ||||
| 
 | ||||
| // 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
 | ||||
| func (suite *ConfigSuite) TestParseInmemory(c *C) { | ||||
| 	suite.expectedConfig.Storage = Storage{"inmemory": Parameters{}} | ||||
| 	suite.expectedConfig.Reporting = Reporting{} | ||||
| 
 | ||||
| 	config, err := Parse(bytes.NewReader([]byte(inmemoryConfigYamlV0_1))) | ||||
| 	c.Assert(err, IsNil) | ||||
|  | @ -171,6 +180,22 @@ func (suite *ConfigSuite) TestParseWithDifferentEnvLoglevel(c *C) { | |||
| 	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
 | ||||
| // version than the CurrentVersion
 | ||||
| func (suite *ConfigSuite) TestParseInvalidVersion(c *C) { | ||||
|  | @ -190,6 +215,10 @@ func copyConfig(config Configuration) *Configuration { | |||
| 	for k, v := range config.Storage.Parameters() { | ||||
| 		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 | ||||
| } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue