switched to chi, also:

* updated healthcheck a bit
* added maintenance mode config toggle
* added recovery handler
This commit is contained in:
2020-10-02 22:40:33 -07:00
parent 9a68d795b2
commit 9f3fb1e944
6 changed files with 164 additions and 42 deletions

View File

@@ -1,26 +1,29 @@
package httpserver
import (
"fmt"
"net/http"
"time"
)
func (s *server) handleHealthCheck() http.HandlerFunc {
type response struct {
Status string `json:"status"`
Now string `json:"now"`
Uptime string `json:"uptime"`
Version string `json:"version"`
Appname string `json:"appname"`
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"`
}
return func(w http.ResponseWriter, req *http.Request) {
resp := &response{
Status: "ok",
Now: time.Now().UTC().Format(time.RFC3339Nano),
Uptime: fmt.Sprintf("%f", s.uptime().Seconds()),
Appname: s.appname,
Version: s.version,
Status: "ok",
Now: time.Now().UTC().Format(time.RFC3339Nano),
UptimeSeconds: int64(s.uptime().Seconds()),
UptimeHuman: s.uptime().String(),
Maintenance: s.maintenance(),
Appname: s.appname,
Version: s.version,
}
s.respondJSON(w, req, resp, 200)
}

View File

@@ -10,12 +10,12 @@ import (
"syscall"
"time"
"github.com/gorilla/mux"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/spf13/viper"
"github.com/getsentry/sentry-go"
"github.com/go-chi/chi"
// spooky action at a distance!
// this populates the environment
@@ -40,7 +40,7 @@ type server struct {
ctx context.Context
cancelFunc context.CancelFunc
httpServer *http.Server
router *mux.Router
router *chi.Mux
}
func NewServer(options ...func(s *server)) *server {
@@ -157,6 +157,10 @@ func (s *server) uptime() time.Duration {
return time.Since(s.startupTime)
}
func (s *server) maintenance() bool {
return viper.GetBool("MAINTENANCE_MODE")
}
func (s *server) configure() {
viper.SetConfigName(s.appname)
viper.SetConfigType("yaml")
@@ -168,6 +172,7 @@ func (s *server) configure() {
viper.AutomaticEnv()
viper.SetDefault("DEBUG", "false")
viper.SetDefault("MAINTENANCE_MODE", "false")
viper.SetDefault("PORT", "8080")
viper.SetDefault("DBURL", "")
@@ -182,7 +187,7 @@ func (s *server) configure() {
}
}
// if viper.GetBool("debug") {
// if viper.GetBool("DEBUG") {
// pp.Print(viper.AllSettings())
// }
}

View File

@@ -4,6 +4,8 @@ import (
"net"
"net/http"
"time"
"github.com/go-chi/chi/middleware"
)
// the following is from
@@ -43,6 +45,7 @@ func (s *server) LoggingMiddleware() func(http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
lrw := NewLoggingResponseWriter(w)
ctx := r.Context()
defer func() {
latency := time.Since(start)
s.log.Info().
@@ -50,11 +53,12 @@ func (s *server) LoggingMiddleware() func(http.Handler) http.Handler {
Str("method", r.Method).
Str("url", r.URL.String()).
Str("useragent", r.UserAgent()).
Str("request_id", ctx.Value(middleware.RequestIDKey).(string)).
Str("referer", r.Referer()).
Str("proto", r.Proto).
Str("remoteIP", ipFromHostPort(r.RemoteAddr)).
Int("status", lrw.statusCode).
Dur("latency", latency).
Int("latency_ms", int(latency.Milliseconds())).
Send()
}()

View File

@@ -1,50 +1,71 @@
package httpserver
import (
"time"
sentryhttp "github.com/getsentry/sentry-go/http"
"github.com/gorilla/mux"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
)
func (s *server) routes() {
s.router = mux.NewRouter()
s.router = chi.NewRouter()
authMiddleware := s.AuthMiddleware()
s.router.HandleFunc("/", s.handleIndex()).Methods("GET")
// if you want to use a general purpose middleware (http.Handler
// wrapper) on a specific HandleFunc route, you need to take the
// .ServeHTTP of the http.Handler to get its HandleFunc, viz:
s.router.HandleFunc(
"/login",
authMiddleware(s.handleLogin()).ServeHTTP,
).Methods("GET")
s.router.HandleFunc(
"/.well-known/healthcheck.json",
s.handleHealthCheck(),
).Methods("GET")
// route that panics for testing
// CHANGEME remove this
s.router.HandleFunc(
"/panic",
s.handlePanic(),
).Methods("GET")
// the Gorilla mux .Use() takes a http.Handler wrapper func, like
// the mux .Use() takes a http.Handler wrapper func, like
// most things that deal with "middlewares" like alice et c, and
// will call ServeHTTP on it. These middlewares applied by the mux
// (you can .Use() more than one) will be applied to every request
// into the service.
s.router.Use(middleware.RequestID)
s.router.Use(s.LoggingMiddleware())
// timeout for request context
s.router.Use(middleware.Timeout(60 * time.Second))
// this adds a sentry reporting middleware if and only if
// sentry is enabled via setting of SENTRY_DSN in env.
// this was at the bottom, but chi requires *all* middlewares
// applied before any routes are, so now it's up here.
// unfortunately this cannot coexist with the normal chi Recoverer
// handler which prints a nice stack trace to the console
if s.sentryEnabled {
// Options docs at
// https://docs.sentry.io/platforms/go/guides/http/
sentryHandler := sentryhttp.New(sentryhttp.Options{})
s.router.Use(sentryHandler.Handle)
// FYI: the sentry panic-catcher seems to set the response
// code to 200.
} else {
// FYI: the chi Recoverer middleware sets the response code
// on panics to 500.
s.router.Use(middleware.Recoverer)
}
////////////////////////////////////////////////////////////////////////
// ROUTES
// complete docs: https://github.com/go-chi/chi
////////////////////////////////////////////////////////////////////////
s.router.Get("/", s.handleIndex())
// if you want to use a general purpose middleware (http.Handler
// wrapper) on a specific HandleFunc route, you need to take the
// .ServeHTTP of the http.Handler to get its HandleFunc, viz:
authMiddleware := s.AuthMiddleware()
s.router.Get(
"/login",
authMiddleware(s.handleLogin()).ServeHTTP,
)
s.router.Get(
"/.well-known/healthcheck.json",
s.handleHealthCheck(),
)
// route that panics for testing
// CHANGEME remove this
s.router.Get(
"/panic",
s.handlePanic(),
)
}