@@ -13,6 +13,7 @@ import (
13
13
"github.com/grafana/metrictank/idx/memory"
14
14
"github.com/grafana/metrictank/schema"
15
15
"github.com/tinylib/msgp/msgp"
16
+ "golang.org/x/sync/errgroup"
16
17
macaron "gopkg.in/macaron.v1"
17
18
18
19
"github.com/grafana/metrictank/api/middleware"
@@ -371,6 +372,75 @@ func (s *Server) metricsFind(ctx *middleware.Context, request models.GraphiteFin
371
372
}
372
373
}
373
374
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
+
374
444
func (s * Server ) listLocal (orgId uint32 ) []idx.Archive {
375
445
376
446
// query nodes have no data
0 commit comments