package healthcheck import ( "context" "encoding/json" "net/http" "time" "github.com/rs/zerolog" "go.uber.org/fx" "sneak.berlin/go/directory/internal/config" "sneak.berlin/go/directory/internal/database" "sneak.berlin/go/directory/internal/globals" "sneak.berlin/go/directory/internal/logger" ) type HealthcheckParams struct { fx.In Globals *globals.Globals Config *config.Config Logger *logger.Logger Database *database.Database } type Healthcheck struct { StartupTime time.Time log *zerolog.Logger params *HealthcheckParams } func New(lc fx.Lifecycle, params HealthcheckParams) (*Healthcheck, error) { s := new(Healthcheck) s.params = ¶ms s.log = params.Logger.Get() lc.Append(fx.Hook{ OnStart: func(ctx context.Context) error { s.StartupTime = time.Now() return nil }, OnStop: func(ctx context.Context) error { // FIXME do server shutdown here return nil }, }) return s, nil } func (s *Healthcheck) uptime() time.Duration { return time.Since(s.StartupTime) } type HealthcheckResponse struct { Status string `json:"status"` Now string `json:"now"` UptimeSeconds int64 `json:"uptime_seconds"` UptimeHuman string `json:"uptime_human"` Version string `json:"version"` Appname string `json:"appname"` Maintenance bool `json:"maintenance_mode"` } func (s *Healthcheck) Healthcheck() *HealthcheckResponse { resp := &HealthcheckResponse{ Status: "ok", Now: time.Now().UTC().Format(time.RFC3339Nano), UptimeSeconds: int64(s.uptime().Seconds()), UptimeHuman: s.uptime().String(), Appname: s.params.Globals.Appname, Version: s.params.Globals.Version, } return resp } func (s *Healthcheck) HealthcheckHandler() http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { resp := s.Healthcheck() w.Header().Set("Content-Type", "application/json; charset=utf-8") json.NewEncoder(w).Encode(resp) } }