now does logging and auth middleware
This commit is contained in:
parent
eaa2f2b929
commit
7bf1aee60f
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.15
|
||||
|
||||
require (
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/justinas/alice v1.2.0
|
||||
github.com/rs/zerolog v1.20.0
|
||||
github.com/spf13/viper v1.7.1
|
||||
)
|
||||
|
2
go.sum
2
go.sum
@ -96,6 +96,8 @@ github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCV
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/justinas/alice v1.2.0 h1:+MHSA/vccVCF4Uq37S42jwlkvI2Xzl7zTPCN5BnZNVo=
|
||||
github.com/justinas/alice v1.2.0/go.mod h1:fN5HRH/reO/zrUflLfTN43t3vXvKzvZIENsNEe7i7qA=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
12
httpserver/handleadmin.go
Normal file
12
httpserver/handleadmin.go
Normal file
@ -0,0 +1,12 @@
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (s *server) handleLogin() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
fmt.Fprintf(w, "hello login")
|
||||
}
|
||||
}
|
@ -6,8 +6,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
func (s *server) serveUntilShutdown() {
|
||||
@ -24,9 +22,9 @@ func (s *server) serveUntilShutdown() {
|
||||
// this does any necessary setup in each handler
|
||||
s.routes()
|
||||
|
||||
log.Info().Str("listenaddr", listenAddr).Msg("http begin listen")
|
||||
s.log.Info().Str("listenaddr", listenAddr).Msg("http begin listen")
|
||||
if err := s.httpServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
|
||||
log.Error().Msgf("listen:%+s\n", err)
|
||||
s.log.Error().Msgf("listen:%+s\n", err)
|
||||
if s.cancelFunc != nil {
|
||||
s.cancelFunc()
|
||||
}
|
||||
@ -39,22 +37,21 @@ func (s *server) respondJSON(w http.ResponseWriter, r *http.Request, data interf
|
||||
if data != nil {
|
||||
err := json.NewEncoder(w).Encode(data)
|
||||
if err != nil {
|
||||
log.Error().Err(err).Msg("json encode error")
|
||||
s.log.Error().Err(err).Msg("json encode error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) decodeJSON(w http.ResponseWriter, r *http.Request, v interface{}) error {
|
||||
func (s *server) decodeJSON(w http.ResponseWriter, r *http.Request, v interface{}) error { // nolint
|
||||
return json.NewDecoder(r.Body).Decode(v)
|
||||
}
|
||||
|
||||
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
// FIXME logging or any other general purpose middleware here
|
||||
s.router.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (s *server) cleanupForExit() {
|
||||
log.Info().Msg("cleaning up")
|
||||
s.log.Info().Msg("cleaning up")
|
||||
// FIXME unimplemented
|
||||
// close database connections or whatever
|
||||
}
|
||||
@ -62,11 +59,14 @@ func (s *server) cleanupForExit() {
|
||||
func (s *server) cleanShutdown() {
|
||||
// initiate clean shutdown
|
||||
s.exitCode = 0
|
||||
ctxShutdown, _ := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
ctxShutdown, shutdownCancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
if err := s.httpServer.Shutdown(ctxShutdown); err != nil {
|
||||
log.Error().
|
||||
s.log.Error().
|
||||
Err(err).
|
||||
Msg("server clean shutdown failed")
|
||||
}
|
||||
if shutdownCancel != nil {
|
||||
shutdownCancel()
|
||||
}
|
||||
s.cleanupForExit()
|
||||
}
|
||||
|
@ -66,12 +66,12 @@ func (s *server) serve() int {
|
||||
|
||||
// signal watcher
|
||||
go func() {
|
||||
c := make(chan os.Signal)
|
||||
c := make(chan os.Signal, 1)
|
||||
signal.Ignore(syscall.SIGPIPE)
|
||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||
// block and wait for signal
|
||||
sig := <-c
|
||||
log.Info().Msgf("signal received: %+v", sig)
|
||||
s.log.Info().Msgf("signal received: %+v", sig)
|
||||
if s.cancelFunc != nil {
|
||||
// cancelling the main context will trigger a clean
|
||||
// shutdown.
|
||||
@ -81,15 +81,12 @@ func (s *server) serve() int {
|
||||
|
||||
go s.serveUntilShutdown()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-s.ctx.Done():
|
||||
//aforementioned clean shutdown upon main context
|
||||
//cancellation
|
||||
s.cleanShutdown()
|
||||
return s.exitCode
|
||||
}
|
||||
for range s.ctx.Done() {
|
||||
//aforementioned clean shutdown upon main context
|
||||
//cancellation
|
||||
}
|
||||
s.cleanShutdown()
|
||||
return s.exitCode
|
||||
|
||||
}
|
||||
|
||||
@ -130,7 +127,6 @@ func (s *server) setupLogging() {
|
||||
zerolog.TimestampFunc = func() time.Time {
|
||||
return time.Now().UTC()
|
||||
}
|
||||
log.Logger = log.With().Caller().Logger()
|
||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||
|
||||
tty := false
|
||||
@ -138,11 +134,10 @@ func (s *server) setupLogging() {
|
||||
tty = true
|
||||
}
|
||||
|
||||
log.Info().Bool("tty", tty).Msg("tty detection")
|
||||
|
||||
var writers []io.Writer
|
||||
|
||||
if tty {
|
||||
// this does cool colorization for console/dev
|
||||
consoleWriter := zerolog.NewConsoleWriter(
|
||||
func(w *zerolog.ConsoleWriter) {
|
||||
// Customize time format
|
||||
@ -152,10 +147,13 @@ func (s *server) setupLogging() {
|
||||
|
||||
writers = append(writers, consoleWriter)
|
||||
} else {
|
||||
// log json in prod for the machines
|
||||
writers = append(writers, os.Stdout)
|
||||
}
|
||||
|
||||
/*
|
||||
// this is how you log to a file, if you do that
|
||||
// sort of thing still
|
||||
logfile := viper.GetString("Logfile")
|
||||
if logfile != "" {
|
||||
logfileDir := filepath.Dir(logfile)
|
||||
@ -170,24 +168,24 @@ func (s *server) setupLogging() {
|
||||
}
|
||||
|
||||
writers = append(writers, hp.logfh)
|
||||
}
|
||||
*/
|
||||
|
||||
multi := zerolog.MultiLevelWriter(writers...)
|
||||
logger := zerolog.New(multi).With().Timestamp().Logger().With().Caller().Logger()
|
||||
|
||||
log.Logger = logger
|
||||
s.log = &logger
|
||||
//log.Logger = logger
|
||||
|
||||
if viper.GetBool("debug") {
|
||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||
log.Debug().Bool("debug", true).Send()
|
||||
s.log.Debug().Bool("debug", true).Send()
|
||||
}
|
||||
|
||||
s.identify()
|
||||
}
|
||||
|
||||
func (s *server) identify() {
|
||||
log.Info().
|
||||
s.log.Info().
|
||||
Str("appname", s.appname).
|
||||
Str("version", s.version).
|
||||
Str("buildarch", s.buildarch).
|
||||
|
75
httpserver/middlewares.go
Normal file
75
httpserver/middlewares.go
Normal file
@ -0,0 +1,75 @@
|
||||
package httpserver
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
// the following is from
|
||||
// https://learning-cloud-native-go.github.io/docs/a6.adding_zerolog_logger/
|
||||
|
||||
func ipFromHostPort(hp string) string {
|
||||
h, _, err := net.SplitHostPort(hp)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
if len(h) > 0 && h[0] == '[' {
|
||||
return h[1 : len(h)-1]
|
||||
}
|
||||
return h
|
||||
}
|
||||
|
||||
type loggingResponseWriter struct {
|
||||
http.ResponseWriter
|
||||
statusCode int
|
||||
}
|
||||
|
||||
func NewLoggingResponseWriter(w http.ResponseWriter) *loggingResponseWriter {
|
||||
return &loggingResponseWriter{w, http.StatusOK}
|
||||
}
|
||||
|
||||
func (lrw *loggingResponseWriter) WriteHeader(code int) {
|
||||
lrw.statusCode = code
|
||||
lrw.ResponseWriter.WriteHeader(code)
|
||||
}
|
||||
|
||||
// type Middleware func(http.Handler) http.Handler
|
||||
// this returns a Middleware that is designed to do every request through the
|
||||
// mux, note the signature:
|
||||
func (s *server) LoggingMiddleware() func(http.Handler) http.Handler {
|
||||
// FIXME this should use https://github.com/google/go-cloud/blob/master/server/requestlog/requestlog.go
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
start := time.Now()
|
||||
lrw := NewLoggingResponseWriter(w)
|
||||
defer func() {
|
||||
latency := time.Since(start)
|
||||
s.log.Info().
|
||||
Time("request_start", start).
|
||||
Str("method", r.Method).
|
||||
Str("url", r.URL.String()).
|
||||
Str("useragent", r.UserAgent()).
|
||||
Str("referer", r.Referer()).
|
||||
Str("proto", r.Proto).
|
||||
Str("remoteIP", ipFromHostPort(r.RemoteAddr)).
|
||||
Int("status", lrw.statusCode).
|
||||
Dur("latency", latency).
|
||||
Send()
|
||||
|
||||
}()
|
||||
|
||||
next.ServeHTTP(lrw, r)
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// this is the HandleFunc wrapper type for a *specific route*, it doesn't go
|
||||
// on the mux.
|
||||
func (s *server) AuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
s.log.Info().Msg("AUTH: before request")
|
||||
next(w, r)
|
||||
}
|
||||
}
|
@ -1,9 +1,15 @@
|
||||
package httpserver
|
||||
|
||||
import "github.com/gorilla/mux"
|
||||
import (
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
func (s *server) routes() {
|
||||
s.router = mux.NewRouter()
|
||||
|
||||
s.router.HandleFunc("/", s.handleIndex()).Methods("GET")
|
||||
s.router.HandleFunc("/login", s.AuthMiddleware(s.handleLogin())).Methods("GET")
|
||||
s.router.HandleFunc("/.well-known/healthcheck.json", s.handleHealthCheck()).Methods("GET")
|
||||
|
||||
s.router.Use(s.LoggingMiddleware())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user