saturday's cleanups #8
							
								
								
									
										1
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										1
									
								
								go.mod
									
									
									
									
									
								
							@ -3,6 +3,7 @@ module git.eeqj.de/sneak/gohttpserver
 | 
			
		||||
go 1.15
 | 
			
		||||
 | 
			
		||||
require (
 | 
			
		||||
	github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d
 | 
			
		||||
	github.com/getsentry/sentry-go v0.7.0
 | 
			
		||||
	github.com/go-chi/chi v4.1.2+incompatible
 | 
			
		||||
	github.com/joho/godotenv v1.3.0
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								go.sum
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								go.sum
									
									
									
									
									
								
							@ -12,6 +12,8 @@ cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2k
 | 
			
		||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
 | 
			
		||||
contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=
 | 
			
		||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 | 
			
		||||
github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d h1:j6oB/WPCigdOkxtuPl1VSIiLpy7Mdsu6phQffbF19Ng=
 | 
			
		||||
github.com/99designs/basicauth-go v0.0.0-20160802081356-2a93ba0f464d/go.mod h1:3cARGAK9CfW3HoxCy1a0G4TKrdiKke8ftOMEOHyySYs=
 | 
			
		||||
github.com/AndreasBriese/bbloom v0.0.0-20190306092124-e2d15f34fcf9/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8=
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
 | 
			
		||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,6 @@ func Run(appname, version, buildarch string) int {
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// this does nothing if SENTRY_DSN is unset in env.
 | 
			
		||||
	s.enableSentry()
 | 
			
		||||
 | 
			
		||||
	// TODO remove:
 | 
			
		||||
	if s.sentryEnabled {
 | 
			
		||||
@ -75,6 +74,9 @@ func Run(appname, version, buildarch string) int {
 | 
			
		||||
	s.configure()
 | 
			
		||||
	s.setupLogging()
 | 
			
		||||
 | 
			
		||||
	// logging before sentry, because sentry logs
 | 
			
		||||
	s.enableSentry()
 | 
			
		||||
 | 
			
		||||
	s.databaseURL = viper.GetString("DBURL")
 | 
			
		||||
	s.port = viper.GetInt("PORT")
 | 
			
		||||
 | 
			
		||||
@ -82,19 +84,21 @@ func Run(appname, version, buildarch string) int {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (s *server) enableSentry() {
 | 
			
		||||
	sentryDSN := os.Getenv("SENTRY_DSN")
 | 
			
		||||
	if sentryDSN == "" {
 | 
			
		||||
		s.sentryEnabled = false
 | 
			
		||||
	s.sentryEnabled = false
 | 
			
		||||
 | 
			
		||||
	if viper.GetString("SENTRY_DSN") == "" {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	err := sentry.Init(sentry.ClientOptions{
 | 
			
		||||
		Dsn:     sentryDSN,
 | 
			
		||||
		Dsn:     viper.GetString("SENTRY_DSN"),
 | 
			
		||||
		Release: fmt.Sprintf("%s-%s", s.appname, s.version),
 | 
			
		||||
	})
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal().Err(err).Msg("sentry init failure")
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	s.log.Info().Msg("sentry error reporting activated")
 | 
			
		||||
	s.sentryEnabled = true
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -175,6 +179,9 @@ func (s *server) configure() {
 | 
			
		||||
	viper.SetDefault("MAINTENANCE_MODE", "false")
 | 
			
		||||
	viper.SetDefault("PORT", "8080")
 | 
			
		||||
	viper.SetDefault("DBURL", "")
 | 
			
		||||
	viper.SetDefault("SENTRY_DSN", "")
 | 
			
		||||
	viper.SetDefault("METRICS_USERNAME", "")
 | 
			
		||||
	viper.SetDefault("METRICS_PASSWORD", "")
 | 
			
		||||
 | 
			
		||||
	if err := viper.ReadInConfig(); err != nil {
 | 
			
		||||
		if _, ok := err.(viper.ConfigFileNotFoundError); ok {
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,12 @@ import (
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	basicauth "github.com/99designs/basicauth-go"
 | 
			
		||||
	sentryhttp "github.com/getsentry/sentry-go/http"
 | 
			
		||||
	"github.com/go-chi/chi"
 | 
			
		||||
	"github.com/go-chi/chi/middleware"
 | 
			
		||||
	"github.com/prometheus/client_golang/prometheus/promhttp"
 | 
			
		||||
	"github.com/spf13/viper"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func (s *server) routes() {
 | 
			
		||||
@ -20,32 +22,31 @@ func (s *server) routes() {
 | 
			
		||||
	// can .Use() more than one) will be applied to every request into
 | 
			
		||||
	// the service.
 | 
			
		||||
 | 
			
		||||
	s.router.Use(middleware.Recoverer)
 | 
			
		||||
	s.router.Use(middleware.RequestID)
 | 
			
		||||
	s.router.Use(s.LoggingMiddleware())
 | 
			
		||||
	s.router.Use(s.MetricsMiddleware())
 | 
			
		||||
 | 
			
		||||
	// add metrics middleware only if we can serve them behind auth
 | 
			
		||||
	if viper.GetString("METRICS_USERNAME") != "" {
 | 
			
		||||
		s.router.Use(s.MetricsMiddleware())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// CHANGEME to suit your needs, or pull from config.
 | 
			
		||||
	// timeout for request context: your handlers must finish within
 | 
			
		||||
	// timeout for request context; your handlers must finish within
 | 
			
		||||
	// this window:
 | 
			
		||||
	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
 | 
			
		||||
	// colorful stack trace to the console
 | 
			
		||||
	// enabled via setting of SENTRY_DSN in env.
 | 
			
		||||
	if s.sentryEnabled {
 | 
			
		||||
		// Options docs at
 | 
			
		||||
		// https://docs.sentry.io/platforms/go/guides/http/
 | 
			
		||||
		sentryHandler := sentryhttp.New(sentryhttp.Options{})
 | 
			
		||||
		// we set sentry to repanic so that all panics bubble up to the
 | 
			
		||||
		// Recoverer chi middleware above.
 | 
			
		||||
		sentryHandler := sentryhttp.New(sentryhttp.Options{
 | 
			
		||||
			Repanic: true,
 | 
			
		||||
		})
 | 
			
		||||
		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)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	////////////////////////////////////////////////////////////////////////
 | 
			
		||||
@ -58,34 +59,40 @@ func (s *server) routes() {
 | 
			
		||||
	// 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,
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// route that panics for testing
 | 
			
		||||
	// CHANGEME remove this
 | 
			
		||||
	s.router.Get(
 | 
			
		||||
		"/panic",
 | 
			
		||||
		s.handlePanic(),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	s.router.Get(
 | 
			
		||||
		"/.well-known/healthcheck.json",
 | 
			
		||||
		s.handleHealthCheck(),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// route that panics for testing
 | 
			
		||||
	// CHANGEME remove this
 | 
			
		||||
	// set up authenticated /metrics route:
 | 
			
		||||
	if viper.GetString("METRICS_USERNAME") != "" {
 | 
			
		||||
		metricsAuthMiddleware := basicauth.New(
 | 
			
		||||
			"metrics",
 | 
			
		||||
			map[string][]string{
 | 
			
		||||
				viper.GetString("METRICS_USERNAME"): {
 | 
			
		||||
					viper.GetString("METRICS_PASSWORD"),
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		)
 | 
			
		||||
 | 
			
		||||
	s.router.Get(
 | 
			
		||||
		"/panic",
 | 
			
		||||
		s.handlePanic(),
 | 
			
		||||
	)
 | 
			
		||||
 | 
			
		||||
	// CHANGEME you probably want to wrap the following in some kind of
 | 
			
		||||
	// auth like http basic auth which is easy to set up on your
 | 
			
		||||
	// rometheus collector
 | 
			
		||||
	// TODO(sneak): read http basic auth user/pass for /metrics
 | 
			
		||||
	// out of environment vars
 | 
			
		||||
 | 
			
		||||
	s.router.Get(
 | 
			
		||||
		"/metrics",
 | 
			
		||||
		http.HandlerFunc(promhttp.Handler().ServeHTTP),
 | 
			
		||||
	)
 | 
			
		||||
		s.router.Get(
 | 
			
		||||
			"/metrics",
 | 
			
		||||
			metricsAuthMiddleware(
 | 
			
		||||
				http.HandlerFunc(promhttp.Handler().ServeHTTP),
 | 
			
		||||
			).ServeHTTP,
 | 
			
		||||
		)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user