Fixed options parameter, more verbose info output, hit handling on panic

This commit is contained in:
Peter Grlica
2022-03-21 13:06:50 +01:00
parent e4dc6dc5f5
commit d72870a77d
21 changed files with 106 additions and 77 deletions
+1 -1
View File
@@ -491,7 +491,7 @@ func (app *CortezaApp) InitServices(ctx context.Context) (err error) {
corredor.Service().SetRoleFinder(sysService.DefaultRole)
// Initialize API GW bits
apigw.Setup(options.Apigw(), app.Log, app.Store)
apigw.Setup(*options.Apigw(), app.Log, app.Store)
if err = apigw.Service().Reload(ctx); err != nil {
return err
}
+6 -4
View File
@@ -26,12 +26,14 @@ apigw: schema.#optionsGroup & {
description: "Enable extra logging"
}
profiler_enabled: {
type: "bool"
description: "Enable profiler"
type: "bool"
defaultGoExpr: "true"
description: "Enable profiler"
}
profiler_global: {
type: "bool"
description: "Profiler enabled for all routes"
type: "bool"
defaultGoExpr: "false"
description: "Profiler enabled for all routes"
}
log_request_body: {
type: "bool"
+8 -8
View File
@@ -7,17 +7,17 @@ import (
"github.com/cortezaproject/corteza-server/pkg/apigw/types"
)
type ContextKey string
const ContextKeyScope ContextKey = "scope"
const ContextKeyProfiler ContextKey = "profiler"
type (
scopeCtxKey struct{}
profilerCtxKey struct{}
)
func ScopeToContext(ctx context.Context, s *types.Scp) context.Context {
return context.WithValue(ctx, ContextKeyScope, s)
return context.WithValue(ctx, scopeCtxKey{}, s)
}
func ScopeFromContext(ctx context.Context) (ss *types.Scp) {
s := ctx.Value(ContextKeyScope)
s := ctx.Value(scopeCtxKey{})
if s == nil {
return &types.Scp{}
@@ -27,11 +27,11 @@ func ScopeFromContext(ctx context.Context) (ss *types.Scp) {
}
func ProfilerToContext(ctx context.Context, h interface{}) context.Context {
return context.WithValue(ctx, ContextKeyProfiler, h)
return context.WithValue(ctx, profilerCtxKey{}, h)
}
func ProfilerFromContext(ctx context.Context) (h *profiler.Hit) {
hh := ctx.Value(ContextKeyProfiler)
hh := ctx.Value(profilerCtxKey{})
if hh == nil {
return nil
+6 -6
View File
@@ -56,7 +56,7 @@ type (
}
)
func NewRedirection(opts *options.ApigwOpt) (e *redirection) {
func NewRedirection(opts options.ApigwOpt) (e *redirection) {
e = &redirection{}
e.Name = "redirection"
@@ -79,7 +79,7 @@ func NewRedirection(opts *options.ApigwOpt) (e *redirection) {
return
}
func (h redirection) New(opts *options.ApigwOpt) types.Handler {
func (h redirection) New(opts options.ApigwOpt) types.Handler {
return NewRedirection(opts)
}
@@ -129,7 +129,7 @@ func (h redirection) Handler() types.HandlerFunc {
}
}
func NewDefaultJsonResponse(opts *options.ApigwOpt) (e *defaultJsonResponse) {
func NewDefaultJsonResponse(opts options.ApigwOpt) (e *defaultJsonResponse) {
e = &defaultJsonResponse{}
e.Name = "defaultJsonResponse"
@@ -139,7 +139,7 @@ func NewDefaultJsonResponse(opts *options.ApigwOpt) (e *defaultJsonResponse) {
return
}
func (j defaultJsonResponse) New(opts *options.ApigwOpt) types.Handler {
func (j defaultJsonResponse) New(opts options.ApigwOpt) types.Handler {
return NewDefaultJsonResponse(opts)
}
@@ -181,7 +181,7 @@ func checkStatus(typ string, status int) bool {
}
}
func NewJsonResponse(opts *options.ApigwOpt, reg typesRegistry) (e *jsonResponse) {
func NewJsonResponse(opts options.ApigwOpt, reg typesRegistry) (e *jsonResponse) {
e = &jsonResponse{}
e.Name = "jsonResponse"
@@ -201,7 +201,7 @@ func NewJsonResponse(opts *options.ApigwOpt, reg typesRegistry) (e *jsonResponse
return
}
func (j jsonResponse) New(opts *options.ApigwOpt) types.Handler {
func (j jsonResponse) New(opts options.ApigwOpt) types.Handler {
return NewJsonResponse(opts, j.reg)
}
+3 -3
View File
@@ -35,7 +35,7 @@ func Test_redirectionMerge(t *testing.T) {
)
for _, tc := range tcc {
t.Run(tc.name, testMerge(NewRedirection(&options.ApigwOpt{}), tc))
t.Run(tc.name, testMerge(NewRedirection(options.ApigwOpt{}), tc))
}
}
@@ -75,7 +75,7 @@ func Test_redirection(t *testing.T) {
rc = httptest.NewRecorder()
)
h := getHandler(NewRedirection(&options.ApigwOpt{}))
h := getHandler(NewRedirection(options.ApigwOpt{}))
h, err := h.Merge([]byte(tc.expr))
req.NoError(err)
@@ -145,7 +145,7 @@ func Test_jsonResponse(t *testing.T) {
r = r.WithContext(agctx.ScopeToContext(context.Background(), scope))
h := getHandler(NewJsonResponse(&options.ApigwOpt{}, &mockHandlerRegistry{}))
h := getHandler(NewJsonResponse(options.ApigwOpt{}, &mockHandlerRegistry{}))
h, err := h.Merge([]byte(tc.expr))
req.NoError(err)
+7 -7
View File
@@ -41,12 +41,12 @@ type (
}
profiler struct {
opts *options.ApigwOpt
opts options.ApigwOpt
types.FilterMeta
}
)
func NewHeader(opts *options.ApigwOpt) (v *header) {
func NewHeader(opts options.ApigwOpt) (v *header) {
v = &header{}
v.Name = "header"
@@ -64,7 +64,7 @@ func NewHeader(opts *options.ApigwOpt) (v *header) {
return
}
func (h header) New(opts *options.ApigwOpt) types.Handler {
func (h header) New(opts options.ApigwOpt) types.Handler {
return NewHeader(opts)
}
@@ -134,7 +134,7 @@ func (h header) Handler() types.HandlerFunc {
}
}
func NewQueryParam(opts *options.ApigwOpt) (v *queryParam) {
func NewQueryParam(opts options.ApigwOpt) (v *queryParam) {
v = &queryParam{}
v.Name = "queryParam"
@@ -152,7 +152,7 @@ func NewQueryParam(opts *options.ApigwOpt) (v *queryParam) {
return
}
func (qp queryParam) New(opts *options.ApigwOpt) types.Handler {
func (qp queryParam) New(opts options.ApigwOpt) types.Handler {
return NewQueryParam(opts)
}
@@ -222,7 +222,7 @@ func (qp *queryParam) Handler() types.HandlerFunc {
}
}
func NewProfiler(opts *options.ApigwOpt) (pp *profiler) {
func NewProfiler(opts options.ApigwOpt) (pp *profiler) {
pp = &profiler{}
pp.opts = opts
@@ -233,7 +233,7 @@ func NewProfiler(opts *options.ApigwOpt) (pp *profiler) {
return
}
func (pr profiler) New(opts *options.ApigwOpt) types.Handler {
func (pr profiler) New(opts options.ApigwOpt) types.Handler {
return NewProfiler(opts)
}
+7 -7
View File
@@ -37,7 +37,7 @@ func Test_headerMerge(t *testing.T) {
)
for _, tc := range tcc {
t.Run(tc.name, testMerge(NewHeader(&options.ApigwOpt{}), tc))
t.Run(tc.name, testMerge(NewHeader(options.ApigwOpt{}), tc))
}
}
@@ -83,7 +83,7 @@ func Test_headerHandle(t *testing.T) {
r := httptest.NewRequest(http.MethodGet, "/foo", http.NoBody)
r.Header = tc.headers
t.Run(tc.name, testHandle(NewHeader(&options.ApigwOpt{}), r, tc))
t.Run(tc.name, testHandle(NewHeader(options.ApigwOpt{}), r, tc))
}
}
@@ -115,7 +115,7 @@ func Test_queryParamMerge(t *testing.T) {
)
for _, tc := range tcc {
t.Run(tc.name, testMerge(NewQueryParam(&options.ApigwOpt{}), tc))
t.Run(tc.name, testMerge(NewQueryParam(options.ApigwOpt{}), tc))
}
}
@@ -148,7 +148,7 @@ func Test_queryParamHandle(t *testing.T) {
for _, tc := range tcc {
r := httptest.NewRequest(http.MethodGet, tc.url, http.NoBody)
t.Run(tc.name, testHandle(NewQueryParam(&options.ApigwOpt{}), r, tc))
t.Run(tc.name, testHandle(NewQueryParam(options.ApigwOpt{}), r, tc))
}
}
@@ -156,7 +156,7 @@ func Test_profilerHandle_profilerGlobal(t *testing.T) {
type (
tfp struct {
name string
opts *options.ApigwOpt
opts options.ApigwOpt
r *http.Request
exp *h.Request
}
@@ -167,13 +167,13 @@ func Test_profilerHandle_profilerGlobal(t *testing.T) {
tcc = []tfp{
{
name: "skip profiler hit on profiler global = true",
opts: &options.ApigwOpt{ProfilerGlobal: true},
opts: options.ApigwOpt{ProfilerGlobal: true},
r: rr,
exp: nil,
},
{
name: "add profiler hit on profiler global = false",
opts: &options.ApigwOpt{ProfilerGlobal: false},
opts: options.ApigwOpt{ProfilerGlobal: false},
r: rr,
exp: createRequest(rr),
},
+4 -4
View File
@@ -48,7 +48,7 @@ type (
}
)
func NewWorkflow(opts *options.ApigwOpt, wf WfExecer) (p *workflow) {
func NewWorkflow(opts options.ApigwOpt, wf WfExecer) (p *workflow) {
p = &workflow{}
p.d = wf
@@ -68,7 +68,7 @@ func NewWorkflow(opts *options.ApigwOpt, wf WfExecer) (p *workflow) {
return
}
func (h workflow) New(opts *options.ApigwOpt) types.Handler {
func (h workflow) New(opts options.ApigwOpt) types.Handler {
return NewWorkflow(opts, h.d)
}
@@ -152,7 +152,7 @@ func (h workflow) Handler() types.HandlerFunc {
}
}
func NewPayload(opts *options.ApigwOpt, l *zap.Logger) (p *processerPayload) {
func NewPayload(opts options.ApigwOpt, l *zap.Logger) (p *processerPayload) {
p = &processerPayload{}
p.vm = jsenv.New(jsenv.NewTransformer(jsenv.LoaderJS, jsenv.TargetES2016))
@@ -176,7 +176,7 @@ func NewPayload(opts *options.ApigwOpt, l *zap.Logger) (p *processerPayload) {
return
}
func (h processerPayload) New(opts *options.ApigwOpt) types.Handler {
func (h processerPayload) New(opts options.ApigwOpt) types.Handler {
return NewPayload(opts, h.log)
}
+2 -2
View File
@@ -78,7 +78,7 @@ func Test_processerWorkflow(t *testing.T) {
rc = httptest.NewRecorder()
rq, _ = http.NewRequest("POST", "/foo", http.NoBody)
ar, err = h.NewRequest(rq)
pp = NewWorkflow(&options.ApigwOpt{}, tc.wfs)
pp = NewWorkflow(options.ApigwOpt{}, tc.wfs)
)
_, err = pp.Merge([]byte(tc.params))
@@ -173,7 +173,7 @@ func Test_processerPayload(t *testing.T) {
ar, err = h.NewRequest(tc.rq)
)
pp := NewPayload(&options.ApigwOpt{}, zap.NewNop())
pp := NewPayload(options.ApigwOpt{}, zap.NewNop())
_, err = pp.Merge([]byte(tc.params))
if tc.errv != "" {
+2 -2
View File
@@ -46,7 +46,7 @@ type (
}
)
func New(opts *options.ApigwOpt, l *zap.Logger, c *http.Client, s types.SecureStorager) (p *proxy) {
func New(opts options.ApigwOpt, l *zap.Logger, c *http.Client, s types.SecureStorager) (p *proxy) {
p = &proxy{}
p.c = c
@@ -68,7 +68,7 @@ func New(opts *options.ApigwOpt, l *zap.Logger, c *http.Client, s types.SecureSt
return
}
func (h proxy) New(opts *options.ApigwOpt) types.Handler {
func (h proxy) New(opts options.ApigwOpt) types.Handler {
return New(opts, h.log, h.c, h.s)
}
+1 -1
View File
@@ -174,7 +174,7 @@ func Test_proxy(t *testing.T) {
rq = httptest.NewRequest("POST", "/foo", strings.NewReader(`custom request body`))
}
proxy := New(&options.ApigwOpt{}, zap.NewNop(), c, struct{}{})
proxy := New(options.ApigwOpt{}, zap.NewNop(), c, struct{}{})
_, err := proxy.Merge([]byte(tc.params))
req.NoError(err)
+13 -10
View File
@@ -6,29 +6,31 @@ import (
"github.com/cortezaproject/corteza-server/pkg/apigw/profiler"
h "github.com/cortezaproject/corteza-server/pkg/http"
"github.com/cortezaproject/corteza-server/pkg/options"
"go.uber.org/zap"
)
const (
devHelperResponseBody string = `Hey developer!`
)
func helperDefaultResponse(opt *options.ApigwOpt, pr *profiler.Profiler) http.HandlerFunc {
func helperDefaultResponse(opt options.ApigwOpt, pr *profiler.Profiler, log *zap.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
addToProfiler(opt, pr, r, http.StatusNotFound)
addToProfiler(opt, pr, log, r, http.StatusNotFound)
responseBody := ""
if opt.LogEnabled {
// Say something friendly when logging is enabled
http.Error(w, devHelperResponseBody, http.StatusTeapot)
} else {
// Default 404 response
http.Error(w, "", http.StatusNotFound)
responseBody = devHelperResponseBody
}
http.Error(w, responseBody, http.StatusNotFound)
}
}
func helperMethodNotAllowed(opt *options.ApigwOpt, pr *profiler.Profiler) http.HandlerFunc {
func helperMethodNotAllowed(opt options.ApigwOpt, pr *profiler.Profiler, log *zap.Logger) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
addToProfiler(opt, pr, r, http.StatusMethodNotAllowed)
addToProfiler(opt, pr, log, r, http.StatusMethodNotAllowed)
if opt.LogEnabled {
// Say something friendly when logging is enabled
@@ -40,7 +42,7 @@ func helperMethodNotAllowed(opt *options.ApigwOpt, pr *profiler.Profiler) http.H
}
}
func addToProfiler(opt *options.ApigwOpt, pr *profiler.Profiler, r *http.Request, status int) {
func addToProfiler(opt options.ApigwOpt, pr *profiler.Profiler, log *zap.Logger, r *http.Request, status int) {
if !(opt.ProfilerEnabled && opt.ProfilerGlobal) {
return
}
@@ -49,7 +51,8 @@ func addToProfiler(opt *options.ApigwOpt, pr *profiler.Profiler, r *http.Request
ar, err := h.NewRequest(r)
if err != nil {
panic(err)
log.Warn("could not create request wrapper, not adding to profiler")
return
}
h := pr.Hit(ar)
+2 -2
View File
@@ -13,14 +13,14 @@ import (
type (
Registry struct {
opts *options.ApigwOpt
opts options.ApigwOpt
h map[string]types.Handler
}
secureStorageTodo struct{}
)
func NewRegistry(opts *options.ApigwOpt) *Registry {
func NewRegistry(opts options.ApigwOpt) *Registry {
return &Registry{
h: map[string]types.Handler{},
opts: opts,
+4 -4
View File
@@ -11,7 +11,7 @@ import (
func Test_registryAddGet(t *testing.T) {
var (
req = require.New(t)
r = NewRegistry(&options.ApigwOpt{})
r = NewRegistry(options.ApigwOpt{})
)
r.Add("mockHandler", types.MockHandler{})
@@ -26,7 +26,7 @@ func Test_registryAddGet(t *testing.T) {
func Test_registryAddGetErr(t *testing.T) {
var (
req = require.New(t)
r = NewRegistry(&options.ApigwOpt{})
r = NewRegistry(options.ApigwOpt{})
)
r.Add("mockHandler", types.MockHandler{})
@@ -72,7 +72,7 @@ func Test_registryMerge(t *testing.T) {
for _, tc := range tcc {
var (
req = require.New(t)
r = NewRegistry(&options.ApigwOpt{})
r = NewRegistry(options.ApigwOpt{})
)
m, err := r.Merge(types.MockHandler{}, []byte(tc.params))
@@ -90,7 +90,7 @@ func Test_registryMerge(t *testing.T) {
func Test_registryAll(t *testing.T) {
var (
req = require.New(t)
r = NewRegistry(&options.ApigwOpt{})
r = NewRegistry(options.ApigwOpt{})
)
r.Add("mockHandler", types.MockHandler{})
+1 -1
View File
@@ -21,7 +21,7 @@ type (
method string
meta routeMeta
opts *options.ApigwOpt
opts options.ApigwOpt
log *zap.Logger
pr *profiler.Profiler
+1 -1
View File
@@ -95,7 +95,7 @@ func Test_pl(t *testing.T) {
method: tc.method,
endpoint: tc.endpoint,
log: zap.NewNop(),
opts: options.Apigw(),
opts: *options.Apigw(),
handler: pipe.Handler(),
errHandler: pipe.Error(),
}
+34 -10
View File
@@ -28,7 +28,7 @@ type (
}
apigw struct {
opts *options.ApigwOpt
opts options.ApigwOpt
log *zap.Logger
reg *registry.Registry
routes []*route
@@ -48,7 +48,7 @@ func Service() *apigw {
}
// Setup handles the singleton service
func Setup(opts *options.ApigwOpt, log *zap.Logger, storer storer) {
func Setup(opts options.ApigwOpt, log *zap.Logger, storer storer) {
if apiGw != nil {
return
}
@@ -56,7 +56,7 @@ func Setup(opts *options.ApigwOpt, log *zap.Logger, storer storer) {
apiGw = New(opts, log, storer)
}
func New(opts *options.ApigwOpt, logger *zap.Logger, storer storer) *apigw {
func New(opts options.ApigwOpt, logger *zap.Logger, storer storer) *apigw {
var (
pr = profiler.New()
reg = registry.NewRegistry(opts)
@@ -66,7 +66,7 @@ func New(opts *options.ApigwOpt, logger *zap.Logger, storer storer) *apigw {
return &apigw{
opts: opts,
log: logger,
log: logger.Named("http.apigw"),
storer: storer,
reg: reg,
pr: pr,
@@ -84,7 +84,7 @@ func (s *apigw) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
if len(s.routes) == 0 {
helperDefaultResponse(s.opts, s.pr)(w, r)
helperDefaultResponse(s.opts, s.pr, s.log)(w, r)
return
}
@@ -105,12 +105,10 @@ func (s *apigw) Reload(ctx context.Context) (err error) {
routes, err := s.loadRoutes(ctx)
if err != nil {
s.log.Error("could not reload API Gateway routes", zap.Error(err))
s.log.Error("could not reload Integration Gateway routes", zap.Error(err))
return
}
s.log.Debug("reloading API Gateway routes and functions", zap.Int("count", len(routes)))
s.Init(ctx, routes...)
// Rebuild the mux
@@ -125,8 +123,8 @@ func (s *apigw) Reload(ctx context.Context) (err error) {
// profiler gets the missed hit info also
{
var (
defaultMethodResponse = helperMethodNotAllowed(s.opts, s.pr)
defaultResponse = helperDefaultResponse(s.opts, s.pr)
defaultMethodResponse = helperMethodNotAllowed(s.opts, s.pr, s.log)
defaultResponse = helperDefaultResponse(s.opts, s.pr, s.log)
)
s.mx.NotFound(defaultResponse)
@@ -144,6 +142,7 @@ func (s *apigw) Init(ctx context.Context, routes ...*route) {
s.routes = routes
s.loadInfo()
s.log.Debug("registering routes", zap.Int("count", len(s.routes)))
defaultPostFilter, err := s.reg.Get("defaultJsonResponse")
@@ -301,6 +300,31 @@ func (s *apigw) loadFilters(ctx context.Context, route uint64) (ff []*st.ApigwFi
return
}
func (s *apigw) loadInfo() {
s.log.Info("loading Integration Gateway", zap.Bool("debug", s.opts.Debug), zap.Bool("log", s.opts.LogEnabled))
if s.opts.ProfilerEnabled {
if s.opts.LogRequestBody {
s.log.Info("profiler and request body logging is enabled, profiler use is prefered",
zap.Bool("APIGW_PROFILER_ENABLED", s.opts.ProfilerEnabled),
zap.Bool("APIGW_LOG_REQUEST_BODY", s.opts.LogRequestBody))
} else {
s.log.Info("request body logging is enabled, profiler use is prefered (APIGW_PROFILER_ENABLED)",
zap.Bool("APIGW_LOG_REQUEST_BODY", s.opts.LogRequestBody))
}
if !s.opts.ProfilerGlobal {
s.log.Warn("profiler enabled only for routes with a profiler prefilter, use global setting to enable for all (APIGW_PROFILER_GLOBAL)")
}
} else {
if s.opts.ProfilerGlobal {
s.log.Warn("profiler global is enabled, but profiler disabled, no routes will be profiled",
zap.Bool("APIGW_PROFILER_ENABLED", s.opts.ProfilerEnabled),
zap.Bool("APIGW_PROFILER_GLOBAL", s.opts.ProfilerGlobal))
}
}
}
func (s *apigw) Profiler() *profiler.Profiler {
return s.pr
}
+1 -1
View File
@@ -160,7 +160,7 @@ func Test_serviceInit(t *testing.T) {
ctx = context.Background()
)
reg := registry.NewRegistry(&options.ApigwOpt{})
reg := registry.NewRegistry(options.ApigwOpt{})
for hn, h := range tc.reg {
reg.Add(hn, h)
+1 -1
View File
@@ -20,7 +20,7 @@ type (
HTTPHandler
fmt.Stringer
New(*options.ApigwOpt) Handler
New(options.ApigwOpt) Handler
Merge([]byte) (Handler, error)
Meta() FilterMeta
Enabled() bool
+1 -1
View File
@@ -33,7 +33,7 @@ type (
MockRoundTripper func(*http.Request) (*http.Response, error)
)
func (h MockHandler) New(opts *options.ApigwOpt) Handler {
func (h MockHandler) New(opts options.ApigwOpt) Handler {
return MockHandler{}
}
+1 -1
View File
@@ -82,7 +82,7 @@ func InitTestApp() {
r.Group(rest.MountRoutes())
// API gw routes
apigw.Setup(options.Apigw(), service.DefaultLogger, service.DefaultStore)
apigw.Setup(*options.Apigw(), service.DefaultLogger, service.DefaultStore)
err := apigw.Service().Reload(ctx)
if err != nil {
panic(err)