// Package healthcheck provides application health status reporting. package healthcheck import ( "context" "log/slog" "time" "go.uber.org/fx" "sneak.berlin/go/webhooker/internal/config" "sneak.berlin/go/webhooker/internal/database" "sneak.berlin/go/webhooker/internal/globals" "sneak.berlin/go/webhooker/internal/logger" ) //nolint:revive // HealthcheckParams is a standard fx naming convention. type HealthcheckParams struct { fx.In Globals *globals.Globals Config *config.Config Logger *logger.Logger Database *database.Database } // Healthcheck tracks application uptime and reports health status. type Healthcheck struct { StartupTime time.Time log *slog.Logger params *HealthcheckParams } // New creates a Healthcheck that records the startup time on fx // start. 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(_ context.Context) error { s.StartupTime = time.Now() return nil }, OnStop: func(_ context.Context) error { return nil }, }) return s, nil } // Healthcheck returns the current health status of the // application. func (s *Healthcheck) Healthcheck() *Response { resp := &Response{ 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, Maintenance: s.params.Config.MaintenanceMode, } return resp } // Response contains the JSON-serialised health status. type Response struct { Status string `json:"status"` Now string `json:"now"` UptimeSeconds int64 `json:"uptimeSeconds"` UptimeHuman string `json:"uptimeHuman"` Version string `json:"version"` Appname string `json:"appname"` Maintenance bool `json:"maintenanceMode"` } func (s *Healthcheck) uptime() time.Duration { return time.Since(s.StartupTime) }