Skip to content
This repository was archived by the owner on Oct 17, 2020. It is now read-only.

Add instrumentation for Search API #885

Merged
merged 11 commits into from
Jun 26, 2020
26 changes: 26 additions & 0 deletions backend/app/adapter/routing/handle/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"time"

"github.com/short-d/app/fw/router"
"github.com/short-d/short/backend/app/adapter/request"
"github.com/short-d/short/backend/app/entity"
"github.com/short-d/short/backend/app/usecase/authenticator"
"github.com/short-d/short/backend/app/usecase/search"
Expand All @@ -18,6 +19,11 @@ var searchResource = map[string]search.Resource{
"user": search.User,
}

var searchResourceString = map[search.Resource]string{
search.ShortLink: "short_link",
search.User: "user",
}

var searchOrder = map[string]order.By{
"created_time_asc": order.ByCreatedTimeASC,
}
Expand Down Expand Up @@ -62,20 +68,25 @@ type User struct {

// Search fetches resources under certain criteria.
func Search(
instrumentationFactory request.InstrumentationFactory,
searcher search.Search,
authenticator authenticator.Authenticator,
) router.Handle {
return func(w http.ResponseWriter, r *http.Request, params router.Params) {
i := instrumentationFactory.NewHTTP(r)

buf, err := ioutil.ReadAll(r.Body)
defer r.Body.Close()
if err != nil {
i.SearchFailed(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

var body SearchRequest
err = json.Unmarshal(buf, &body)
if err != nil {
i.SearchFailed(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
Expand All @@ -87,24 +98,28 @@ func Search(
}
filter, err := search.NewFilter(body.Filter.MaxResults, body.Filter.Resources, body.Filter.Orders)
if err != nil {
i.SearchFailed(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

results, err := searcher.Search(query, filter)
if err != nil {
i.SearchFailed(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

response := newSearchResponse(results)
respBody, err := json.Marshal(&response)
if err != nil {
i.SearchFailed(err)
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}

w.Write(respBody)
i.SearchSucceed(user, query.Query, body.Filter.resourcesString())
}
}

Expand Down Expand Up @@ -142,6 +157,17 @@ func (f *Filter) UnmarshalJSON(data []byte) error {
return nil
}

func (f *Filter) resourcesString() []string {
var resources []string
for _, resource := range f.Resources {
val, ok := searchResourceString[resource]
if ok {
resources = append(resources, val)
}
}
return resources
}

func newSearchResponse(result search.Result) SearchResponse {
shortLinks := make([]ShortLink, len(result.ShortLinks))
for i := 0; i < len(result.ShortLinks); i++ {
Expand Down
1 change: 1 addition & 0 deletions backend/app/adapter/routing/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ func NewShort(
Method: "POST",
Path: "/search",
Handle: handle.Search(
instrumentationFactory,
search,
authenticator,
),
Expand Down
34 changes: 33 additions & 1 deletion backend/app/usecase/instrumentation/instrumentation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package instrumentation

import (
"fmt"
"strings"

"github.com/short-d/app/fw/analytics"
"github.com/short-d/app/fw/ctx"
Expand All @@ -24,6 +25,8 @@ type Instrumentation struct {
longLinkRetrievalFailedCh chan ctx.ExecutionContext
featureToggleRetrievalSucceedCh chan ctx.ExecutionContext
featureToggleRetrievalFailedCh chan ctx.ExecutionContext
searchSucceedCh chan ctx.ExecutionContext
searchFailedCh chan ctx.ExecutionContext
madeFeatureDecisionCh chan ctx.ExecutionContext
trackCh chan ctx.ExecutionContext
}
Expand Down Expand Up @@ -91,6 +94,29 @@ func (i Instrumentation) FeatureToggleRetrievalFailed(err error) {
}()
}

// SearchSucceed tracks the successes when searching the short resources.
func (i Instrumentation) SearchSucceed(user *entity.User, keywords string, resources []string) {
go func() {
c := <-i.searchSucceedCh
i.metrics.Count("search-succeed", 1, 1, c)
userID := i.getUserID(user)
props := map[string]string{
"keywords": keywords,
"resources": strings.Join(resources, ","),
}
i.analytics.Track("Search", props, userID, c)
}()
}

// SearchFailed tracks the failures when searching the short resources.
func (i Instrumentation) SearchFailed(err error) {
go func() {
c := <-i.searchFailedCh
i.logger.Error(err)
i.metrics.Count("search-failed", 1, 1, c)
}()
}

// MadeFeatureDecision tracks MadeFeatureDecision event.
func (i Instrumentation) MadeFeatureDecision(
featureID string,
Expand Down Expand Up @@ -133,7 +159,7 @@ func (i Instrumentation) getUserID(user *entity.User) string {
if user == nil {
return "anonymous"
}
return user.Email
return user.ID
}

// NewInstrumentation initializes instrumentation code.
Expand All @@ -150,6 +176,8 @@ func NewInstrumentation(
longLinkRetrievalFailedCh := make(chan ctx.ExecutionContext)
featureToggleRetrievalSucceedCh := make(chan ctx.ExecutionContext)
featureToggleRetrievalFailedCh := make(chan ctx.ExecutionContext)
searchSucceedCh := make(chan ctx.ExecutionContext)
searchFailedCh := make(chan ctx.ExecutionContext)
madeFeatureDecisionCh := make(chan ctx.ExecutionContext)
trackCh := make(chan ctx.ExecutionContext)

Expand All @@ -165,6 +193,8 @@ func NewInstrumentation(
longLinkRetrievalFailedCh: longLinkRetrievalFailedCh,
featureToggleRetrievalSucceedCh: featureToggleRetrievalSucceedCh,
featureToggleRetrievalFailedCh: featureToggleRetrievalFailedCh,
searchSucceedCh: searchSucceedCh,
searchFailedCh: searchFailedCh,
madeFeatureDecisionCh: madeFeatureDecisionCh,
trackCh: trackCh,
}
Expand All @@ -176,6 +206,8 @@ func NewInstrumentation(
go func() { longLinkRetrievalFailedCh <- c }()
go func() { featureToggleRetrievalSucceedCh <- c }()
go func() { featureToggleRetrievalFailedCh <- c }()
go func() { searchSucceedCh <- c }()
go func() { searchFailedCh <- c }()
go func() { madeFeatureDecisionCh <- c }()
go func() { trackCh <- c }()
close(ctxCh)
Expand Down