From a64f4c18b3d428bb207ab9f7f95c5a42324a9bab Mon Sep 17 00:00:00 2001 From: Peter Grlica Date: Mon, 9 Jan 2023 13:29:12 +0100 Subject: [PATCH] Added profile purge endpoint --- server/pkg/apigw/profiler/profiler.go | 11 ++++ server/pkg/apigw/profiler/profiler_test.go | 50 ++++++++++++++++ server/pkg/apigw/profiler/purge.go | 7 +++ server/system/rest.yaml | 9 +++ server/system/rest/apigw_profiler.go | 22 +++++++ server/system/rest/handlers/apigwProfiler.go | 38 ++++++++++++ server/system/rest/request/apigwProfiler.go | 61 ++++++++++++++++++++ server/system/service/apigw_profiler.go | 5 ++ 8 files changed, 203 insertions(+) create mode 100644 server/pkg/apigw/profiler/purge.go diff --git a/server/pkg/apigw/profiler/profiler.go b/server/pkg/apigw/profiler/profiler.go index 4a01661c2..2acd577d9 100644 --- a/server/pkg/apigw/profiler/profiler.go +++ b/server/pkg/apigw/profiler/profiler.go @@ -63,6 +63,17 @@ func (p *Profiler) Hits(s Sort) Hits { return ll } +func (p *Profiler) Purge(f *PurgeFilter) { + if f.RouteID == 0 { + p.l = make(Hits, 0) + return + } + + p.l = p.l.Filter(func(k string, v *Hit) bool { + return v.Route != f.RouteID + }) +} + func (p *Profiler) id(r *h.Request) string { return r.URL.Path } diff --git a/server/pkg/apigw/profiler/profiler_test.go b/server/pkg/apigw/profiler/profiler_test.go index 8519b9ad6..c1265b6fb 100644 --- a/server/pkg/apigw/profiler/profiler_test.go +++ b/server/pkg/apigw/profiler/profiler_test.go @@ -111,3 +111,53 @@ func Test_ApigwProfiler_filterHit(t *testing.T) { req.True(found) req.Len(list[id], 1) } + +func Test_ApigwProfiler_purgeAll(t *testing.T) { + var ( + pp = New() + req = require.New(t) + + now = time.Date(2022, time.March, 1, 1, 1, 1, 0, time.UTC) + then = now.Add(-1 * day) + later = now.Add(day) + + hr, _ = h.NewRequest(httptest.NewRequest("POST", "/foo", strings.NewReader(`foo`))) + hr2, _ = h.NewRequest(httptest.NewRequest("GET", "/bar", strings.NewReader(`foo`))) + ) + + pp.Push(&Hit{R: hr, Ts: &then}) + pp.Push(&Hit{R: hr, Ts: &now}) + pp.Push(&Hit{R: hr2, Ts: &now}) + pp.Push(&Hit{R: hr2, Ts: &later}) + pp.Push(&Hit{R: hr2, Ts: &later}) + + req.Len(pp.l, 2) + pp.Purge(&PurgeFilter{}) + req.Len(pp.l, 0) +} + +func Test_ApigwProfiler_purgeRoute(t *testing.T) { + var ( + pp = New() + req = require.New(t) + + now = time.Date(2022, time.March, 1, 1, 1, 1, 0, time.UTC) + then = now.Add(-1 * day) + later = now.Add(day) + + hr, _ = h.NewRequest(httptest.NewRequest("POST", "/foo", strings.NewReader(`foo`))) + hr2, _ = h.NewRequest(httptest.NewRequest("GET", "/bar", strings.NewReader(`foo`))) + ) + + pp.Push(&Hit{Route: 1, R: hr, Ts: &then}) + pp.Push(&Hit{Route: 1, R: hr, Ts: &now}) + pp.Push(&Hit{Route: 2, R: hr2, Ts: &now}) + pp.Push(&Hit{Route: 2, R: hr2, Ts: &later}) + pp.Push(&Hit{Route: 2, R: hr2, Ts: &later}) + + req.Len(pp.l, 2) + + pp.Purge(&PurgeFilter{RouteID: 2}) + + req.Len(pp.l, 1) +} diff --git a/server/pkg/apigw/profiler/purge.go b/server/pkg/apigw/profiler/purge.go new file mode 100644 index 000000000..08cb314a6 --- /dev/null +++ b/server/pkg/apigw/profiler/purge.go @@ -0,0 +1,7 @@ +package profiler + +type ( + PurgeFilter struct { + RouteID uint64 + } +) diff --git a/server/system/rest.yaml b/server/system/rest.yaml index 157d79571..0dfd08d8c 100644 --- a/server/system/rest.yaml +++ b/server/system/rest.yaml @@ -2084,6 +2084,15 @@ endpoints: title: Hit details path: "/hit/{hitID}" parameters: { path: [ { name: hitID, type: string, required: true, title: "Hit ID" } ] } + - name: purge all + method: POST + title: Purge all profiler hits + path: "/purge" + - name: purge + method: POST + title: Purge route profiler hits + path: "/purge/{routeID}" + parameters: { path: [ { name: routeID, type: "uint64", title: "Route ID", required: true } ] } - title: Locale entrypoint: locale diff --git a/server/system/rest/apigw_profiler.go b/server/system/rest/apigw_profiler.go index dc560d05a..3a993b1fe 100644 --- a/server/system/rest/apigw_profiler.go +++ b/server/system/rest/apigw_profiler.go @@ -3,6 +3,7 @@ package rest import ( "context" + "github.com/cortezaproject/corteza/server/pkg/apigw/profiler" "github.com/cortezaproject/corteza/server/pkg/filter" "github.com/cortezaproject/corteza/server/system/rest/request" "github.com/cortezaproject/corteza/server/system/service" @@ -13,6 +14,7 @@ type ( profilerService interface { Hits(context.Context, types.ApigwProfilerFilter) (types.ApigwProfilerHitSet, types.ApigwProfilerFilter, error) HitsAggregated(context.Context, types.ApigwProfilerFilter) (types.ApigwProfilerAggregationSet, types.ApigwProfilerFilter, error) + Purge(context.Context, *profiler.PurgeFilter) } ApigwProfiler struct { @@ -109,6 +111,26 @@ func (ctrl *ApigwProfiler) Hit(ctx context.Context, r *request.ApigwProfilerHit) return ctrl.makeRoutePayload(ctx, set[0], err) } +func (ctrl *ApigwProfiler) PurgeAll(ctx context.Context, r *request.ApigwProfilerPurgeAll) (_ interface{}, _ error) { + var ( + f = &profiler.PurgeFilter{} + ) + + ctrl.svc.Purge(ctx, f) + return +} + +func (ctrl *ApigwProfiler) Purge(ctx context.Context, r *request.ApigwProfilerPurge) (_ interface{}, _ error) { + var ( + f = &profiler.PurgeFilter{ + RouteID: r.RouteID, + } + ) + + ctrl.svc.Purge(ctx, f) + return +} + func (ctrl *ApigwProfiler) makePayload(ctx context.Context, q *types.ApigwProfilerAggregation, err error) (*profilerHitPayload, error) { if err != nil || q == nil { return nil, err diff --git a/server/system/rest/handlers/apigwProfiler.go b/server/system/rest/handlers/apigwProfiler.go index 90d0206f8..f41266e94 100644 --- a/server/system/rest/handlers/apigwProfiler.go +++ b/server/system/rest/handlers/apigwProfiler.go @@ -22,6 +22,8 @@ type ( Aggregation(context.Context, *request.ApigwProfilerAggregation) (interface{}, error) Route(context.Context, *request.ApigwProfilerRoute) (interface{}, error) Hit(context.Context, *request.ApigwProfilerHit) (interface{}, error) + PurgeAll(context.Context, *request.ApigwProfilerPurgeAll) (interface{}, error) + Purge(context.Context, *request.ApigwProfilerPurge) (interface{}, error) } // HTTP API interface @@ -29,6 +31,8 @@ type ( Aggregation func(http.ResponseWriter, *http.Request) Route func(http.ResponseWriter, *http.Request) Hit func(http.ResponseWriter, *http.Request) + PurgeAll func(http.ResponseWriter, *http.Request) + Purge func(http.ResponseWriter, *http.Request) } ) @@ -80,6 +84,38 @@ func NewApigwProfiler(h ApigwProfilerAPI) *ApigwProfiler { return } + api.Send(w, r, value) + }, + PurgeAll: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewApigwProfilerPurgeAll() + if err := params.Fill(r); err != nil { + api.Send(w, r, err) + return + } + + value, err := h.PurgeAll(r.Context(), params) + if err != nil { + api.Send(w, r, err) + return + } + + api.Send(w, r, value) + }, + Purge: func(w http.ResponseWriter, r *http.Request) { + defer r.Body.Close() + params := request.NewApigwProfilerPurge() + if err := params.Fill(r); err != nil { + api.Send(w, r, err) + return + } + + value, err := h.Purge(r.Context(), params) + if err != nil { + api.Send(w, r, err) + return + } + api.Send(w, r, value) }, } @@ -91,5 +127,7 @@ func (h ApigwProfiler) MountRoutes(r chi.Router, middlewares ...func(http.Handle r.Get("/apigw/profiler/", h.Aggregation) r.Get("/apigw/profiler/route/{routeID}", h.Route) r.Get("/apigw/profiler/hit/{hitID}", h.Hit) + r.Post("/apigw/profiler/purge", h.PurgeAll) + r.Post("/apigw/profiler/purge/{routeID}", h.Purge) }) } diff --git a/server/system/rest/request/apigwProfiler.go b/server/system/rest/request/apigwProfiler.go index 00d751fc8..8b65519dc 100644 --- a/server/system/rest/request/apigwProfiler.go +++ b/server/system/rest/request/apigwProfiler.go @@ -88,6 +88,16 @@ type ( // Hit ID HitID string } + + ApigwProfilerPurgeAll struct { + } + + ApigwProfilerPurge struct { + // RouteID PATH parameter + // + // Route ID + RouteID uint64 `json:",string"` + } ) // NewApigwProfilerAggregation request @@ -284,3 +294,54 @@ func (r *ApigwProfilerHit) Fill(req *http.Request) (err error) { return err } + +// NewApigwProfilerPurgeAll request +func NewApigwProfilerPurgeAll() *ApigwProfilerPurgeAll { + return &ApigwProfilerPurgeAll{} +} + +// Auditable returns all auditable/loggable parameters +func (r ApigwProfilerPurgeAll) Auditable() map[string]interface{} { + return map[string]interface{}{} +} + +// Fill processes request and fills internal variables +func (r *ApigwProfilerPurgeAll) Fill(req *http.Request) (err error) { + + return err +} + +// NewApigwProfilerPurge request +func NewApigwProfilerPurge() *ApigwProfilerPurge { + return &ApigwProfilerPurge{} +} + +// Auditable returns all auditable/loggable parameters +func (r ApigwProfilerPurge) Auditable() map[string]interface{} { + return map[string]interface{}{ + "routeID": r.RouteID, + } +} + +// Auditable returns all auditable/loggable parameters +func (r ApigwProfilerPurge) GetRouteID() uint64 { + return r.RouteID +} + +// Fill processes request and fills internal variables +func (r *ApigwProfilerPurge) Fill(req *http.Request) (err error) { + + { + var val string + // path params + + val = chi.URLParam(req, "routeID") + r.RouteID, err = payload.ParseUint64(val), nil + if err != nil { + return err + } + + } + + return err +} diff --git a/server/system/service/apigw_profiler.go b/server/system/service/apigw_profiler.go index cbf8dd316..c7f55d3bf 100644 --- a/server/system/service/apigw_profiler.go +++ b/server/system/service/apigw_profiler.go @@ -192,6 +192,11 @@ func (svc *apigwProfiler) HitsAggregated(ctx context.Context, filter types.Apigw return } +func (svc *apigwProfiler) Purge(ctx context.Context, f *profiler.PurgeFilter) { + apigw.Service().Profiler().Purge(f) + return +} + func sortAggregation(list *types.ApigwProfilerAggregationSet, filter *types.ApigwProfilerFilter) { for _, ff := range sortAggFields { fe := filter.Sort.Get(ff)