Skip to content
This repository was archived by the owner on Aug 23, 2023. It is now read-only.

Commit 6c3706a

Browse files
authored
Merge pull request #1795 from grafana/metrics_expand
implement /metrics/expand endpoint
2 parents be6b494 + 4434106 commit 6c3706a

File tree

6 files changed

+433
-0
lines changed

6 files changed

+433
-0
lines changed

api/graphite.go

+70
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"github.com/grafana/metrictank/idx/memory"
1414
"github.com/grafana/metrictank/schema"
1515
"github.com/tinylib/msgp/msgp"
16+
"golang.org/x/sync/errgroup"
1617
macaron "gopkg.in/macaron.v1"
1718

1819
"github.com/grafana/metrictank/api/middleware"
@@ -371,6 +372,75 @@ func (s *Server) metricsFind(ctx *middleware.Context, request models.GraphiteFin
371372
}
372373
}
373374

375+
func (s *Server) metricsExpand(ctx *middleware.Context, request models.GraphiteExpand) {
376+
g, errGroupCtx := errgroup.WithContext(ctx.Req.Context())
377+
results := make([]map[string]struct{}, len(request.Query))
378+
for i, query := range request.Query {
379+
i, query := i, query
380+
g.Go(func() error {
381+
series, err := s.findSeries(errGroupCtx, ctx.OrgId, []string{query}, 0)
382+
if err != nil {
383+
return err
384+
}
385+
results[i] = make(map[string]struct{})
386+
for _, s := range series {
387+
for _, n := range s.Series {
388+
if request.LeavesOnly && !n.Leaf {
389+
continue
390+
}
391+
392+
results[i][n.Path] = struct{}{}
393+
}
394+
}
395+
return nil
396+
})
397+
}
398+
if err := g.Wait(); err != nil {
399+
response.Write(ctx, response.WrapError(err))
400+
return
401+
}
402+
403+
// check to see if the request has been canceled, if so abort now.
404+
select {
405+
case <-ctx.Req.Context().Done():
406+
//request canceled
407+
response.Write(ctx, response.RequestCanceledErr)
408+
return
409+
default:
410+
}
411+
412+
if request.GroupByExpr {
413+
// keyed by query string
414+
resultsGrouped := make(map[string][]string, len(results))
415+
for resultIdx, queryResults := range results {
416+
// query and results can be associated via their shared idx
417+
query := request.Query[resultIdx]
418+
resultsGrouped[query] = make([]string, 0, len(queryResults))
419+
for queryResult := range queryResults {
420+
resultsGrouped[query] = append(resultsGrouped[query], queryResult)
421+
}
422+
sort.StringSlice(resultsGrouped[query]).Sort()
423+
}
424+
425+
response.Write(ctx, response.NewJson(200, resultsGrouped, request.Jsonp))
426+
} else {
427+
// all results in one flat list
428+
resultsUngrouped := make(map[string]struct{})
429+
for _, paths := range results {
430+
for path := range paths {
431+
resultsUngrouped[path] = struct{}{}
432+
}
433+
}
434+
resultSlice := make([]string, 0, len(resultsUngrouped))
435+
for result := range resultsUngrouped {
436+
resultSlice = append(resultSlice, result)
437+
}
438+
sort.StringSlice(resultSlice).Sort()
439+
440+
response.Write(ctx, response.NewJson(200, resultSlice, request.Jsonp))
441+
}
442+
}
443+
374444
func (s *Server) listLocal(orgId uint32) []idx.Archive {
375445

376446
// query nodes have no data

api/models/graphite.go

+7
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,13 @@ type GraphiteFind struct {
182182
Jsonp string `json:"jsonp" form:"jsonp"`
183183
}
184184

185+
type GraphiteExpand struct {
186+
Query []string `json:"query" form:"query" binding:"Required"`
187+
GroupByExpr bool `json:"groupByExpr" form:"groupByExpr"`
188+
LeavesOnly bool `json:"leavesOnly" form:"leavesOnly"`
189+
Jsonp string `json:"jsonp" form:"jsonp"`
190+
}
191+
185192
type MetricsDelete struct {
186193
Query string `json:"query" form:"query" binding:"Required"`
187194
}

api/models/graphite_gen.go

+218
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)