// Start checks the modules for the following interfaces and registers and/or starts: // Startable: // health.Checker: // Endpoint: Register the handler function of the Endpoint in the http service at prefix func (s *Service) Start() error { el := protocol.NewErrorList("service: errors occured while starting: ") if s.healthEndpoint != "" { loggerService.WithField("healthEndpoint", s.healthEndpoint).Info("Health endpoint") s.webserver.Handle(s.healthEndpoint, http.HandlerFunc(health.StatusHandler)) } else { loggerService.Info("Health endpoint disabled") } if s.metricsEndpoint != "" { loggerService.WithField("metricsEndpoint", s.metricsEndpoint).Info("Metrics endpoint") s.webserver.Handle(s.metricsEndpoint, http.HandlerFunc(metrics.HttpHandler)) } else { loggerService.Info("Metrics endpoint disabled") } for _, module := range s.modules { name := reflect.TypeOf(module).String() if startable, ok := module.(Startable); ok { loggerService.WithFields(log.Fields{ "name": name, }).Info("Starting module") if err := startable.Start(); err != nil { loggerService.WithFields(log.Fields{ "name": name, "err": err, }).Error("Error while starting module") el.Add(err) } } if checker, ok := module.(health.Checker); ok && s.healthEndpoint != "" { loggerService.WithField("name", name).Info("Registering module as Health-Checker") health.RegisterPeriodicThresholdFunc(name, s.healthFrequency, s.healthThreshold, health.CheckFunc(checker.Check)) } if endpoint, ok := module.(Endpoint); ok { prefix := endpoint.GetPrefix() loggerService.WithFields(log.Fields{ "name": name, "prefix": prefix, }).Info("Registering module as Endpoint") s.webserver.Handle(prefix, endpoint) } } return el.ErrorOrNil() }
// Start checks the modules for the following interfaces and registers and/or starts: // Startable: // health.Checker: // Endpoint: Register the handler function of the Endpoint in the http service at prefix func (s *Service) Start() error { var multierr *multierror.Error if s.healthEndpoint != "" { logger.WithField("healthEndpoint", s.healthEndpoint).Info("Health endpoint") s.webserver.Handle(s.healthEndpoint, http.HandlerFunc(health.StatusHandler)) } else { logger.Info("Health endpoint disabled") } if s.metricsEndpoint != "" { logger.WithField("metricsEndpoint", s.metricsEndpoint).Info("Metrics endpoint") s.webserver.Handle(s.metricsEndpoint, http.HandlerFunc(metrics.HttpHandler)) } else { logger.Info("Metrics endpoint disabled") } for order, iface := range s.ModulesSortedByStartOrder() { name := reflect.TypeOf(iface).String() if s, ok := iface.(Startable); ok { logger.WithFields(log.Fields{"name": name, "order": order}).Info("Starting module") if err := s.Start(); err != nil { logger.WithError(err).WithField("name", name).Error("Error while starting module") multierr = multierror.Append(multierr, err) } } else { logger.WithFields(log.Fields{"name": name, "order": order}).Debug("Module is not startable") } if c, ok := iface.(health.Checker); ok && s.healthEndpoint != "" { logger.WithField("name", name).Info("Registering module as Health-Checker") health.RegisterPeriodicThresholdFunc(name, s.healthFrequency, s.healthThreshold, health.CheckFunc(c.Check)) } if e, ok := iface.(Endpoint); ok { prefix := e.GetPrefix() logger.WithFields(log.Fields{"name": name, "prefix": prefix}).Info("Registering module as Endpoint") s.webserver.Handle(prefix, e) } } return multierr.ErrorOrNil() }
// RegisterHealthChecks is an awful hack to defer health check registration // control to callers. This should only ever be called once per registry // process, typically in a main function. The correct way would be register // health checks outside of app, since multiple apps may exist in the same // process. Because the configuration and app are tightly coupled, // implementing this properly will require a refactor. This method may panic // if called twice in the same process. func (app *App) RegisterHealthChecks() { health.RegisterPeriodicThresholdFunc("storagedriver_"+app.Config.Storage.Type(), 10*time.Second, 3, func() error { _, err := app.driver.List(app, "/") // "/" should always exist return err // any error will be treated as failure }) }