add http middleware, add option to use custom mux, improved logger kvs

This commit is contained in:
Adphi 2021-10-13 17:05:59 +02:00
parent 2916a61b3b
commit 43357bc790
9 changed files with 72 additions and 15 deletions

View File

@ -9,10 +9,12 @@ import (
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strings" "strings"
"time"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"go.linka.cloud/grpc/client" "go.linka.cloud/grpc/client"
"go.linka.cloud/grpc/logger"
"go.linka.cloud/grpc/registry/mdns" "go.linka.cloud/grpc/registry/mdns"
"go.linka.cloud/grpc/service" "go.linka.cloud/grpc/service"
) )
@ -39,6 +41,20 @@ func (g *GreeterHandler) SayHelloStream(req *HelloStreamRequest, s Greeter_SayHe
return nil return nil
} }
func httpLogger(next http.Handler) http.Handler {
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
start := time.Now()
log := logger.From(request.Context()).WithFields(
"method", request.Method,
"host", request.Host,
"path", request.URL.Path,
"remoteAddress", request.RemoteAddr,
)
next.ServeHTTP(writer, request)
log.WithField("duration", time.Since(start)).Info()
})
}
func main() { func main() {
name := "greeter" name := "greeter"
secure := true secure := true
@ -71,6 +87,7 @@ func main() {
service.WithGatewayPrefix("/rest"), service.WithGatewayPrefix("/rest"),
service.WithGRPCWeb(true), service.WithGRPCWeb(true),
service.WithGRPCWebPrefix("/grpc"), service.WithGRPCWebPrefix("/grpc"),
service.WithMiddlewares(httpLogger),
) )
if err != nil { if err != nil {
panic(err) panic(err)
@ -142,4 +159,3 @@ func main() {
cancel() cancel()
<-done <-done
} }

2
go.mod
View File

@ -13,9 +13,11 @@ require (
github.com/iancoleman/strcase v0.2.0 // indirect github.com/iancoleman/strcase v0.2.0 // indirect
github.com/improbable-eng/grpc-web v0.14.1 github.com/improbable-eng/grpc-web v0.14.1
github.com/jinzhu/gorm v1.9.12 github.com/jinzhu/gorm v1.9.12
github.com/justinas/alice v1.2.0
github.com/lyft/protoc-gen-star v0.6.0 // indirect github.com/lyft/protoc-gen-star v0.6.0 // indirect
github.com/miekg/dns v1.1.35 github.com/miekg/dns v1.1.35
github.com/planetscale/vtprotobuf v0.2.0 github.com/planetscale/vtprotobuf v0.2.0
github.com/rs/cors v1.7.0
github.com/sirupsen/logrus v1.8.1 github.com/sirupsen/logrus v1.8.1
github.com/soheilhy/cmux v0.1.5 github.com/soheilhy/cmux v0.1.5
github.com/spf13/cobra v1.0.0 github.com/spf13/cobra v1.0.0

2
go.sum
View File

@ -368,6 +368,8 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
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/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
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/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00= github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=

View File

@ -1,6 +1,8 @@
package logger package logger
import ( import (
"fmt"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
) )
@ -14,7 +16,7 @@ func New() Logger {
type Logger interface { type Logger interface {
WithField(key string, value interface{}) Logger WithField(key string, value interface{}) Logger
WithFields(kv ...string) Logger WithFields(kv ...interface{}) Logger
WithError(err error) Logger WithError(err error) Logger
Debugf(format string, args ...interface{}) Debugf(format string, args ...interface{})
@ -53,9 +55,9 @@ func (l *logger) WithField(key string, value interface{}) Logger {
return &logger{FieldLogger: l.FieldLogger.WithField(key, value)} return &logger{FieldLogger: l.FieldLogger.WithField(key, value)}
} }
func (l *logger) WithFields(kv ...string) Logger { func (l *logger) WithFields(kv ...interface{}) Logger {
for i := 0; i < len(kv); i += 2 { for i := 0; i < len(kv); i += 2 {
l.FieldLogger = l.FieldLogger.WithField(kv[i], kv[i+1]) l.FieldLogger = l.FieldLogger.WithField(fmt.Sprintf("%v", kv[i]), kv[i+1])
} }
return l return l
} }

View File

@ -21,9 +21,9 @@ func (s *service) gateway(opts ...runtime.ServeMuxOption) error {
return err return err
} }
if s.opts.gatewayPrefix != "" { if s.opts.gatewayPrefix != "" {
s.mux.Handle(s.opts.gatewayPrefix+"/", http.StripPrefix(s.opts.gatewayPrefix, mux)) s.opts.mux.Handle(s.opts.gatewayPrefix+"/", http.StripPrefix(s.opts.gatewayPrefix, mux))
} else { } else {
s.mux.Handle("/", mux) s.opts.mux.Handle("/", mux)
} }
return nil return nil
} }

15
service/mux.go Normal file
View File

@ -0,0 +1,15 @@
package service
import (
"net/http"
"github.com/justinas/alice"
)
type ServeMux interface {
ServeHTTP(http.ResponseWriter, *http.Request)
Handle(pattern string, handler http.Handler)
HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
}
type Middleware = alice.Constructor

View File

@ -83,8 +83,8 @@ type Options interface {
ClientInterceptors() []grpc.UnaryClientInterceptor ClientInterceptors() []grpc.UnaryClientInterceptor
StreamClientInterceptors() []grpc.StreamClientInterceptor StreamClientInterceptors() []grpc.StreamClientInterceptor
Cors() cors.Options Cors() cors.Options
Mux() ServeMux
GRPCWeb() bool GRPCWeb() bool
GRPCWebPrefix() string GRPCWebPrefix() string
GRPCWebOpts() []grpcweb.Option GRPCWebOpts() []grpcweb.Option
@ -266,6 +266,18 @@ func WithCors(opts cors.Options) Option {
} }
} }
func WithMux(mux ServeMux) Option {
return func(o *options) {
o.mux = mux
}
}
func WithMiddlewares(m ...Middleware) Option {
return func(o *options) {
o.middlewares = m
}
}
func WithGRPCWeb(b bool) Option { func WithGRPCWeb(b bool) Option {
return func(o *options) { return func(o *options) {
o.grpcWeb = b o.grpcWeb = b
@ -334,6 +346,8 @@ type options struct {
clientInterceptors []grpc.UnaryClientInterceptor clientInterceptors []grpc.UnaryClientInterceptor
streamClientInterceptors []grpc.StreamClientInterceptor streamClientInterceptors []grpc.StreamClientInterceptor
mux ServeMux
middlewares []Middleware
grpcWeb bool grpcWeb bool
grpcWebOpts []grpcweb.Option grpcWebOpts []grpcweb.Option
grpcWebPrefix string grpcWebPrefix string
@ -433,6 +447,10 @@ func (o *options) Cors() cors.Options {
return o.cors return o.cors
} }
func (o *options) Mux() ServeMux {
return o.mux
}
func (o *options) GRPCWeb() bool { func (o *options) GRPCWeb() bool {
return o.grpcWeb return o.grpcWeb
} }

View File

@ -18,6 +18,7 @@ import (
"github.com/google/uuid" "github.com/google/uuid"
grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
"github.com/jinzhu/gorm" "github.com/jinzhu/gorm"
"github.com/justinas/alice"
"github.com/rs/cors" "github.com/rs/cors"
"github.com/sirupsen/logrus" "github.com/sirupsen/logrus"
"github.com/soheilhy/cmux" "github.com/soheilhy/cmux"
@ -54,7 +55,6 @@ type service struct {
mu sync.Mutex mu sync.Mutex
running bool running bool
mux *http.ServeMux
// inproc Channel is used to serve grpc gateway // inproc Channel is used to serve grpc gateway
inproc *inprocgrpc.Channel inproc *inprocgrpc.Channel
@ -71,7 +71,6 @@ func newService(opts ...Option) (*service, error) {
opts: parseFlags(NewOptions()), opts: parseFlags(NewOptions()),
cmd: cmd, cmd: cmd,
id: uuid.New().String(), id: uuid.New().String(),
mux: http.NewServeMux(),
inproc: &inprocgrpc.Channel{}, inproc: &inprocgrpc.Channel{},
} }
s.mu.Lock() s.mu.Lock()
@ -79,6 +78,9 @@ func newService(opts ...Option) (*service, error) {
for _, f := range opts { for _, f := range opts {
f(s.opts) f(s.opts)
} }
if s.opts.mux == nil {
s.opts.mux = http.NewServeMux()
}
if s.opts.error != nil { if s.opts.error != nil {
return nil, s.opts.error return nil, s.opts.error
} }
@ -194,7 +196,7 @@ func (s *service) run() error {
} }
} }
hServer := &http.Server{ hServer := &http.Server{
Handler: cors.New(s.opts.cors).Handler(s.mux), Handler: alice.New(s.opts.middlewares...).Then(cors.New(s.opts.cors).Handler(s.opts.mux)),
} }
if s.opts.Gateway() || s.opts.grpcWeb { if s.opts.Gateway() || s.opts.grpcWeb {
go func() { go func() {

View File

@ -26,9 +26,9 @@ func (s *service) grpcWeb(opts ...grpcweb.Option) error {
h := grpcweb.WrapServer(s.server, append(defaultWebOptions, opts...)...) h := grpcweb.WrapServer(s.server, append(defaultWebOptions, opts...)...)
for _, v := range grpcweb.ListGRPCResources(s.server) { for _, v := range grpcweb.ListGRPCResources(s.server) {
if s.opts.grpcWebPrefix != "" { if s.opts.grpcWebPrefix != "" {
s.mux.Handle(s.opts.grpcWebPrefix+v, http.StripPrefix(s.opts.grpcWebPrefix, h)) s.opts.mux.Handle(s.opts.grpcWebPrefix+v, http.StripPrefix(s.opts.grpcWebPrefix, h))
} else { } else {
s.mux.Handle(v, h) s.opts.mux.Handle(v, h)
} }
} }
return nil return nil