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 (
|
require (
|
||||||
github.com/gorilla/mux v1.8.0
|
github.com/gorilla/mux v1.8.0
|
||||||
|
github.com/justinas/alice v1.2.0
|
||||||
github.com/rs/zerolog v1.20.0
|
github.com/rs/zerolog v1.20.0
|
||||||
github.com/spf13/viper v1.7.1
|
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/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/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/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/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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=
|
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"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/rs/zerolog/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s *server) serveUntilShutdown() {
|
func (s *server) serveUntilShutdown() {
|
||||||
@ -24,9 +22,9 @@ func (s *server) serveUntilShutdown() {
|
|||||||
// this does any necessary setup in each handler
|
// this does any necessary setup in each handler
|
||||||
s.routes()
|
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 {
|
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 {
|
if s.cancelFunc != nil {
|
||||||
s.cancelFunc()
|
s.cancelFunc()
|
||||||
}
|
}
|
||||||
@ -39,22 +37,21 @@ func (s *server) respondJSON(w http.ResponseWriter, r *http.Request, data interf
|
|||||||
if data != nil {
|
if data != nil {
|
||||||
err := json.NewEncoder(w).Encode(data)
|
err := json.NewEncoder(w).Encode(data)
|
||||||
if err != nil {
|
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)
|
return json.NewDecoder(r.Body).Decode(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
// FIXME logging or any other general purpose middleware here
|
|
||||||
s.router.ServeHTTP(w, r)
|
s.router.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) cleanupForExit() {
|
func (s *server) cleanupForExit() {
|
||||||
log.Info().Msg("cleaning up")
|
s.log.Info().Msg("cleaning up")
|
||||||
// FIXME unimplemented
|
// FIXME unimplemented
|
||||||
// close database connections or whatever
|
// close database connections or whatever
|
||||||
}
|
}
|
||||||
@ -62,11 +59,14 @@ func (s *server) cleanupForExit() {
|
|||||||
func (s *server) cleanShutdown() {
|
func (s *server) cleanShutdown() {
|
||||||
// initiate clean shutdown
|
// initiate clean shutdown
|
||||||
s.exitCode = 0
|
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 {
|
if err := s.httpServer.Shutdown(ctxShutdown); err != nil {
|
||||||
log.Error().
|
s.log.Error().
|
||||||
Err(err).
|
Err(err).
|
||||||
Msg("server clean shutdown failed")
|
Msg("server clean shutdown failed")
|
||||||
}
|
}
|
||||||
|
if shutdownCancel != nil {
|
||||||
|
shutdownCancel()
|
||||||
|
}
|
||||||
s.cleanupForExit()
|
s.cleanupForExit()
|
||||||
}
|
}
|
||||||
|
@ -66,12 +66,12 @@ func (s *server) serve() int {
|
|||||||
|
|
||||||
// signal watcher
|
// signal watcher
|
||||||
go func() {
|
go func() {
|
||||||
c := make(chan os.Signal)
|
c := make(chan os.Signal, 1)
|
||||||
signal.Ignore(syscall.SIGPIPE)
|
signal.Ignore(syscall.SIGPIPE)
|
||||||
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
|
||||||
// block and wait for signal
|
// block and wait for signal
|
||||||
sig := <-c
|
sig := <-c
|
||||||
log.Info().Msgf("signal received: %+v", sig)
|
s.log.Info().Msgf("signal received: %+v", sig)
|
||||||
if s.cancelFunc != nil {
|
if s.cancelFunc != nil {
|
||||||
// cancelling the main context will trigger a clean
|
// cancelling the main context will trigger a clean
|
||||||
// shutdown.
|
// shutdown.
|
||||||
@ -81,15 +81,12 @@ func (s *server) serve() int {
|
|||||||
|
|
||||||
go s.serveUntilShutdown()
|
go s.serveUntilShutdown()
|
||||||
|
|
||||||
for {
|
for range s.ctx.Done() {
|
||||||
select {
|
//aforementioned clean shutdown upon main context
|
||||||
case <-s.ctx.Done():
|
//cancellation
|
||||||
//aforementioned clean shutdown upon main context
|
|
||||||
//cancellation
|
|
||||||
s.cleanShutdown()
|
|
||||||
return s.exitCode
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
s.cleanShutdown()
|
||||||
|
return s.exitCode
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -130,7 +127,6 @@ func (s *server) setupLogging() {
|
|||||||
zerolog.TimestampFunc = func() time.Time {
|
zerolog.TimestampFunc = func() time.Time {
|
||||||
return time.Now().UTC()
|
return time.Now().UTC()
|
||||||
}
|
}
|
||||||
log.Logger = log.With().Caller().Logger()
|
|
||||||
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
zerolog.SetGlobalLevel(zerolog.InfoLevel)
|
||||||
|
|
||||||
tty := false
|
tty := false
|
||||||
@ -138,11 +134,10 @@ func (s *server) setupLogging() {
|
|||||||
tty = true
|
tty = true
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Info().Bool("tty", tty).Msg("tty detection")
|
|
||||||
|
|
||||||
var writers []io.Writer
|
var writers []io.Writer
|
||||||
|
|
||||||
if tty {
|
if tty {
|
||||||
|
// this does cool colorization for console/dev
|
||||||
consoleWriter := zerolog.NewConsoleWriter(
|
consoleWriter := zerolog.NewConsoleWriter(
|
||||||
func(w *zerolog.ConsoleWriter) {
|
func(w *zerolog.ConsoleWriter) {
|
||||||
// Customize time format
|
// Customize time format
|
||||||
@ -152,10 +147,13 @@ func (s *server) setupLogging() {
|
|||||||
|
|
||||||
writers = append(writers, consoleWriter)
|
writers = append(writers, consoleWriter)
|
||||||
} else {
|
} else {
|
||||||
|
// log json in prod for the machines
|
||||||
writers = append(writers, os.Stdout)
|
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")
|
logfile := viper.GetString("Logfile")
|
||||||
if logfile != "" {
|
if logfile != "" {
|
||||||
logfileDir := filepath.Dir(logfile)
|
logfileDir := filepath.Dir(logfile)
|
||||||
@ -170,24 +168,24 @@ func (s *server) setupLogging() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
writers = append(writers, hp.logfh)
|
writers = append(writers, hp.logfh)
|
||||||
}
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
multi := zerolog.MultiLevelWriter(writers...)
|
multi := zerolog.MultiLevelWriter(writers...)
|
||||||
logger := zerolog.New(multi).With().Timestamp().Logger().With().Caller().Logger()
|
logger := zerolog.New(multi).With().Timestamp().Logger().With().Caller().Logger()
|
||||||
|
|
||||||
log.Logger = logger
|
s.log = &logger
|
||||||
|
//log.Logger = logger
|
||||||
|
|
||||||
if viper.GetBool("debug") {
|
if viper.GetBool("debug") {
|
||||||
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
zerolog.SetGlobalLevel(zerolog.DebugLevel)
|
||||||
log.Debug().Bool("debug", true).Send()
|
s.log.Debug().Bool("debug", true).Send()
|
||||||
}
|
}
|
||||||
|
|
||||||
s.identify()
|
s.identify()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) identify() {
|
func (s *server) identify() {
|
||||||
log.Info().
|
s.log.Info().
|
||||||
Str("appname", s.appname).
|
Str("appname", s.appname).
|
||||||
Str("version", s.version).
|
Str("version", s.version).
|
||||||
Str("buildarch", s.buildarch).
|
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
|
package httpserver
|
||||||
|
|
||||||
import "github.com/gorilla/mux"
|
import (
|
||||||
|
"github.com/gorilla/mux"
|
||||||
|
)
|
||||||
|
|
||||||
func (s *server) routes() {
|
func (s *server) routes() {
|
||||||
s.router = mux.NewRouter()
|
s.router = mux.NewRouter()
|
||||||
|
|
||||||
s.router.HandleFunc("/", s.handleIndex()).Methods("GET")
|
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.HandleFunc("/.well-known/healthcheck.json", s.handleHealthCheck()).Methods("GET")
|
||||||
|
|
||||||
|
s.router.Use(s.LoggingMiddleware())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user