You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@servicecomb.apache.org by ti...@apache.org on 2020/03/14 07:29:17 UTC

[servicecomb-kie] branch master updated: refactor polling detail (#116)

This is an automated email from the ASF dual-hosted git repository.

tianxiaoliang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/servicecomb-kie.git


The following commit(s) were added to refs/heads/master by this push:
     new 758438e  refactor polling detail (#116)
758438e is described below

commit 758438ee79060094456208a411bbc653c3e3a912
Author: Shawn <xi...@gmail.com>
AuthorDate: Sat Mar 14 15:29:09 2020 +0800

    refactor polling detail (#116)
---
 examples/dev/conf/chassis.yaml                    |   2 +-
 pkg/common/common.go                              |   1 +
 scripts/start.sh                                  |   2 +-
 server/handler/track_handler.go                   | 118 ++++++++++++++++++++++
 server/resource/v1/common.go                      |  18 ++--
 server/resource/v1/kv_resource.go                 |  92 +++++------------
 server/service/mongo/record/polling_detail_dao.go |   2 +
 7 files changed, 158 insertions(+), 77 deletions(-)

diff --git a/examples/dev/conf/chassis.yaml b/examples/dev/conf/chassis.yaml
index 2b22ce9..d5c8888 100755
--- a/examples/dev/conf/chassis.yaml
+++ b/examples/dev/conf/chassis.yaml
@@ -10,7 +10,7 @@ cse:
   handler:
     chain:
       Provider:
-        default: auth-handler,ratelimiter-provider
+        default: auth-handler,track-handler,ratelimiter-provider
 # ssl:
 #   Provider.cipherPlugin: default
 #   Provider.verifyPeer: false
diff --git a/pkg/common/common.go b/pkg/common/common.go
index 4cdf3fc..191d627 100644
--- a/pkg/common/common.go
+++ b/pkg/common/common.go
@@ -27,6 +27,7 @@ const (
 	QueryParamRev    = "revision"
 	QueryParamMatch  = "match"
 	QueryParamKeyID  = "kv_id"
+	QueryParamLabel  = "label"
 	QueryParamStatus = "status"
 	QueryParamOffset = "offset"
 	QueryParamLimit  = "limit"
diff --git a/scripts/start.sh b/scripts/start.sh
index 9abf470..3f230e0 100755
--- a/scripts/start.sh
+++ b/scripts/start.sh
@@ -38,7 +38,7 @@ cse:
   handler:
     chain:
       Provider:
-        default: auth-handler,ratelimiter-provider
+        default: auth-handler,track-handler,ratelimiter-provider
 EOM
 cat <<EOM > ${root_dir}/conf/lager.yaml
 logger_level: ${LOG_LEVEL}
diff --git a/server/handler/track_handler.go b/server/handler/track_handler.go
new file mode 100644
index 0000000..f85df93
--- /dev/null
+++ b/server/handler/track_handler.go
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package handler
+
+import (
+	"github.com/apache/servicecomb-kie/pkg/common"
+	"github.com/apache/servicecomb-kie/pkg/iputil"
+	"github.com/apache/servicecomb-kie/pkg/model"
+	"github.com/apache/servicecomb-kie/server/resource/v1"
+	"github.com/apache/servicecomb-kie/server/service/mongo/record"
+	"github.com/emicklei/go-restful"
+	"github.com/go-chassis/go-chassis/core/handler"
+	"github.com/go-chassis/go-chassis/core/invocation"
+	"github.com/go-mesh/openlogging"
+	"net/http"
+	"strings"
+)
+
+//const of noop auth handler
+const (
+	TrackHandlerName = "track-handler"
+)
+
+//TrackHandler tracks polling data
+type TrackHandler struct{}
+
+//Handle set local attribute to http request
+func (h *TrackHandler) Handle(chain *handler.Chain, inv *invocation.Invocation, cb invocation.ResponseCallBack) {
+	req, ok := inv.Args.(*restful.Request)
+	if !ok {
+		chain.Next(inv, cb)
+		return
+	}
+	if req.Request.Method != http.MethodGet {
+		chain.Next(inv, cb)
+		return
+	}
+	if !strings.Contains(req.Request.URL.Path, "kie/kv") {
+		chain.Next(inv, cb)
+		return
+	}
+	sessionID := req.HeaderParameter(v1.HeaderSessionID)
+	if sessionID == "" {
+		chain.Next(inv, cb)
+		return
+	}
+	chain.Next(inv, func(ir *invocation.Response) error {
+		resp, ok := ir.Result.(*restful.Response)
+		if !ok {
+			err := cb(ir)
+			if err != nil {
+				return err
+			}
+			return nil
+		}
+		revStr := req.QueryParameter(common.QueryParamRev)
+		wait := req.QueryParameter(common.QueryParamWait)
+		data := &model.PollingDetail{}
+		data.URLPath = req.Request.Method + " " + req.Request.URL.Path
+		data.SessionID = sessionID
+		data.UserAgent = req.HeaderParameter(v1.HeaderUserAgent)
+		data.Domain = inv.Metadata[v1.AttributeDomainKey].(string)
+		data.IP = iputil.ClientIP(req.Request)
+		data.ResponseBody = inv.Ctx.Value(common.RespBodyContextKey)
+		data.ResponseCode = ir.Status
+		data.ResponseHeader = resp.Header()
+		data.PollingData = map[string]interface{}{
+			"revStr":  revStr,
+			"wait":    wait,
+			"project": req.HeaderParameter(v1.PathParameterProject),
+			"labels":  req.QueryParameter("label"),
+		}
+		_, err := record.CreateOrUpdate(inv.Ctx, data)
+		if err != nil {
+			openlogging.Warn("record polling detail failed" + err.Error())
+			err := cb(ir)
+			if err != nil {
+				return err
+			}
+			return nil
+		}
+		err = cb(ir)
+		if err != nil {
+			return err
+		}
+		return nil
+	})
+
+}
+
+func newTrackHandler() handler.Handler {
+	return &TrackHandler{}
+}
+
+//Name is handler name
+func (h *TrackHandler) Name() string {
+	return TrackHandlerName
+}
+func init() {
+	if err := handler.RegisterHandler(TrackHandlerName, newTrackHandler); err != nil {
+		openlogging.Fatal("register handler failed: " + err.Error())
+	}
+}
diff --git a/server/resource/v1/common.go b/server/resource/v1/common.go
index 8fda4b8..957308f 100644
--- a/server/resource/v1/common.go
+++ b/server/resource/v1/common.go
@@ -21,6 +21,7 @@ import (
 	"context"
 	"encoding/json"
 	"errors"
+	"github.com/apache/servicecomb-kie/pkg/model"
 	"net/http"
 	"strconv"
 	"strings"
@@ -129,7 +130,7 @@ func writeResponse(ctx *restful.Context, v interface{}) error {
 	return ctx.WriteJSON(v, goRestful.MIME_JSON) // json is default
 }
 func getLabels(rctx *restful.Context) (map[string]string, error) {
-	labelSlice := rctx.Req.QueryParameters("label")
+	labelSlice := rctx.Req.QueryParameters(common.QueryParamLabel)
 	if len(labelSlice) == 0 {
 		return nil, nil
 	}
@@ -220,27 +221,26 @@ func checkStatus(status string) (string, error) {
 	return status, nil
 }
 
-func queryAndResponse(rctx *restful.Context,
-	domain interface{}, project string, key string, labels map[string]string, offset, limit int64, status string) {
+func queryAndResponse(rctx *restful.Context, doc *model.KVDoc, offset, limit int64) {
 	m := getMatchPattern(rctx)
 	opts := []service.FindOption{
-		service.WithKey(key),
-		service.WithLabels(labels),
+		service.WithKey(doc.Key),
+		service.WithLabels(doc.Labels),
 		service.WithOffset(offset),
 		service.WithLimit(limit),
 	}
 	if m == common.PatternExact {
 		opts = append(opts, service.WithExactLabels())
 	}
-	if status != "" {
-		opts = append(opts, service.WithStatus(status))
+	if doc.Status != "" {
+		opts = append(opts, service.WithStatus(doc.Status))
 	}
-	rev, err := service.RevisionService.GetRevision(rctx.Ctx, domain.(string))
+	rev, err := service.RevisionService.GetRevision(rctx.Ctx, doc.Domain)
 	if err != nil {
 		WriteErrResponse(rctx, http.StatusInternalServerError, err.Error(), common.ContentTypeText)
 		return
 	}
-	kv, err := service.KVService.List(rctx.Ctx, domain.(string), project, opts...)
+	kv, err := service.KVService.List(rctx.Ctx, doc.Domain, doc.Project, opts...)
 	if err != nil {
 		if err == service.ErrKeyNotExists {
 			rctx.ReadResponseWriter().Header().Set(common.HeaderRevision, strconv.FormatInt(rev, 10))
diff --git a/server/resource/v1/kv_resource.go b/server/resource/v1/kv_resource.go
index aa77096..e4d883e 100644
--- a/server/resource/v1/kv_resource.go
+++ b/server/resource/v1/kv_resource.go
@@ -23,15 +23,12 @@ import (
 	"net/http"
 
 	"github.com/apache/servicecomb-kie/pkg/common"
-	"github.com/apache/servicecomb-kie/pkg/iputil"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/pubsub"
 	"github.com/apache/servicecomb-kie/server/service"
-	"github.com/apache/servicecomb-kie/server/service/mongo/record"
 	goRestful "github.com/emicklei/go-restful"
 	"github.com/go-chassis/go-chassis/server/restful"
 	"github.com/go-mesh/openlogging"
-	uuid "github.com/satori/go.uuid"
 )
 
 //KVResource has API about kv operations
@@ -49,10 +46,6 @@ func (r *KVResource) Put(context *restful.Context) {
 		return
 	}
 	domain := ReadDomain(context)
-	if domain == nil {
-		WriteErrResponse(context, http.StatusInternalServerError, common.MsgDomainMustNotBeEmpty, common.ContentTypeText)
-		return
-	}
 	kv.Key = key
 	kv.Domain = domain.(string)
 	kv.Project = project
@@ -101,10 +94,6 @@ func (r *KVResource) GetByKey(rctx *restful.Context) {
 		return
 	}
 	domain := ReadDomain(rctx)
-	if domain == nil {
-		WriteErrResponse(rctx, http.StatusInternalServerError, common.MsgDomainMustNotBeEmpty, common.ContentTypeText)
-		return
-	}
 	offsetStr := rctx.ReadQueryParameter(common.QueryParamOffset)
 	limitStr := rctx.ReadQueryParameter(common.QueryParamLimit)
 	offset, limit, err := checkPagination(offsetStr, limitStr)
@@ -112,14 +101,20 @@ func (r *KVResource) GetByKey(rctx *restful.Context) {
 		WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
 		return
 	}
-	insID := rctx.ReadHeader(HeaderSessionID)
+	sessionID := rctx.ReadHeader(HeaderSessionID)
 	statusStr := rctx.ReadQueryParameter(common.QueryParamStatus)
 	status, err := checkStatus(statusStr)
 	if err != nil {
 		WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
 		return
 	}
-	returnData(rctx, domain, project, key, labels, offset, limit, status, insID)
+	returnData(rctx, &model.KVDoc{
+		Domain:  domain.(string),
+		Project: project,
+		Key:     key,
+		Labels:  labels,
+		Status:  status,
+	}, offset, limit, sessionID)
 }
 
 //List response kv list
@@ -127,10 +122,6 @@ func (r *KVResource) List(rctx *restful.Context) {
 	var err error
 	project := rctx.ReadPathParameter(PathParameterProject)
 	domain := ReadDomain(rctx)
-	if domain == nil {
-		WriteErrResponse(rctx, http.StatusInternalServerError, common.MsgDomainMustNotBeEmpty, common.ContentTypeText)
-		return
-	}
 	labels, err := getLabels(rctx)
 	if err != nil {
 		WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
@@ -150,37 +141,39 @@ func (r *KVResource) List(rctx *restful.Context) {
 		WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
 		return
 	}
-	returnData(rctx, domain, project, "", labels, offset, limit, status, sessionID)
+	returnData(rctx, &model.KVDoc{
+		Domain:  domain.(string),
+		Project: project,
+		Labels:  labels,
+		Status:  status,
+	}, offset, limit, sessionID)
 }
 
-func returnData(rctx *restful.Context, domain interface{}, project, key string, labels map[string]string, offset, limit int64, status, sessionID string) {
+func returnData(rctx *restful.Context, doc *model.KVDoc, offset, limit int64, sessionID string) {
 	revStr := rctx.ReadQueryParameter(common.QueryParamRev)
 	wait := rctx.ReadQueryParameter(common.QueryParamWait)
-	if sessionID != "" {
-		defer RecordPollingDetail(rctx, revStr, wait, domain.(string), project, labels, offset, limit, sessionID)
-	}
 	if revStr == "" {
 		if wait == "" {
-			queryAndResponse(rctx, domain, project, key, labels, offset, limit, status)
+			queryAndResponse(rctx, doc, offset, limit)
 			return
 		}
 		changed, err := eventHappened(rctx, wait, &pubsub.Topic{
-			Labels:    labels,
-			Project:   project,
+			Labels:    doc.Labels,
+			Project:   doc.Project,
 			MatchType: getMatchPattern(rctx),
-			DomainID:  domain.(string),
+			DomainID:  doc.Domain,
 		})
 		if err != nil {
 			WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
 			return
 		}
 		if changed {
-			queryAndResponse(rctx, domain, project, key, labels, offset, limit, status)
+			queryAndResponse(rctx, doc, offset, limit)
 			return
 		}
 		rctx.WriteHeader(http.StatusNotModified)
 	} else {
-		revised, err := isRevised(rctx.Ctx, revStr, domain.(string))
+		revised, err := isRevised(rctx.Ctx, revStr, doc.Domain)
 		if err != nil {
 			if err == ErrInvalidRev {
 				WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
@@ -190,21 +183,21 @@ func returnData(rctx *restful.Context, domain interface{}, project, key string,
 			return
 		}
 		if revised {
-			queryAndResponse(rctx, domain, project, key, labels, offset, limit, status)
+			queryAndResponse(rctx, doc, offset, limit)
 			return
 		} else if wait != "" {
 			changed, err := eventHappened(rctx, wait, &pubsub.Topic{
-				Labels:    labels,
-				Project:   project,
+				Labels:    doc.Labels,
+				Project:   doc.Project,
 				MatchType: getMatchPattern(rctx),
-				DomainID:  domain.(string),
+				DomainID:  doc.Domain,
 			})
 			if err != nil {
 				WriteErrResponse(rctx, http.StatusBadRequest, err.Error(), common.ContentTypeText)
 				return
 			}
 			if changed {
-				queryAndResponse(rctx, domain, project, key, labels, offset, limit, status)
+				queryAndResponse(rctx, doc, offset, limit)
 				return
 			}
 			rctx.WriteHeader(http.StatusNotModified)
@@ -215,43 +208,10 @@ func returnData(rctx *restful.Context, domain interface{}, project, key string,
 	}
 }
 
-//RecordPollingDetail to record data after get or list
-func RecordPollingDetail(context *restful.Context, revStr, wait, domain, project string, labels map[string]string, limit, offset int64, sessionID string) {
-	data := &model.PollingDetail{}
-	data.ID = uuid.NewV4().String()
-	data.SessionID = sessionID
-	data.Domain = domain
-	data.IP = iputil.ClientIP(context.Req.Request)
-	dataMap := map[string]interface{}{
-		"revStr":  revStr,
-		"wait":    wait,
-		"domain":  domain,
-		"project": project,
-		"labels":  labels,
-		"limit":   limit,
-		"offset":  offset,
-	}
-	data.PollingData = dataMap
-	data.UserAgent = context.Req.HeaderParameter(HeaderUserAgent)
-	data.URLPath = context.ReadRequest().Method + " " + context.ReadRequest().URL.Path
-	data.ResponseHeader = context.Resp.Header()
-	data.ResponseCode = context.Resp.StatusCode()
-	data.ResponseBody = context.Ctx.Value(common.RespBodyContextKey)
-	_, err := record.CreateOrUpdate(context.Ctx, data)
-	if err != nil {
-		openlogging.Warn("record polling detail failed" + err.Error())
-		return
-	}
-}
-
 //Delete deletes key by ids
 func (r *KVResource) Delete(context *restful.Context) {
 	project := context.ReadPathParameter(PathParameterProject)
 	domain := ReadDomain(context)
-	if domain == nil {
-		WriteErrResponse(context, http.StatusInternalServerError, common.MsgDomainMustNotBeEmpty, common.ContentTypeText)
-		return
-	}
 	kvID := context.ReadQueryParameter(common.QueryParamKeyID)
 	if kvID == "" {
 		WriteErrResponse(context, http.StatusBadRequest, common.ErrKvIDMustNotEmpty, common.ContentTypeText)
diff --git a/server/service/mongo/record/polling_detail_dao.go b/server/service/mongo/record/polling_detail_dao.go
index 3e76bcb..6cefe5c 100644
--- a/server/service/mongo/record/polling_detail_dao.go
+++ b/server/service/mongo/record/polling_detail_dao.go
@@ -21,6 +21,7 @@ import (
 	"context"
 	"github.com/apache/servicecomb-kie/pkg/model"
 	"github.com/apache/servicecomb-kie/server/service/mongo/session"
+	uuid "github.com/satori/go.uuid"
 	"go.mongodb.org/mongo-driver/bson"
 	"go.mongodb.org/mongo-driver/mongo"
 )
@@ -32,6 +33,7 @@ func CreateOrUpdate(ctx context.Context, detail *model.PollingDetail) (*model.Po
 	res := collection.FindOne(ctx, queryFilter)
 	if res.Err() != nil {
 		if res.Err() == mongo.ErrNoDocuments {
+			detail.ID = uuid.NewV4().String()
 			_, err := collection.InsertOne(ctx, detail)
 			if err != nil {
 				return nil, err