func query( request *tsdbjson.QueryRequest, endpoints *datastructs.ApplicationStatuses, minDownSampleTime time.Duration) ( result []tsdbjson.TimeSeries, err error) { parsedQueries, err := tsdbjson.ParseQueryRequest(request) if err != nil { return } var allSeries []tsdbjson.TimeSeries for i := range parsedQueries { var options tsdbimpl.QueryOptions options.HostNameFilter, err = newTagFilter( parsedQueries[i].Options.HostNameFilter) if err != nil { return } options.AppNameFilter, err = newTagFilter( parsedQueries[i].Options.AppNameFilter) if err != nil { return } options.GroupByAppName = parsedQueries[i].Options.GroupByAppName options.GroupByHostName = parsedQueries[i].Options.GroupByHostName if parsedQueries[i].Aggregator.DownSample == nil { return nil, tsdbjson.ErrUnsupportedAggregator } ensureDurationAtLeast( duration.ToFloat(minDownSampleTime), &parsedQueries[i].Aggregator.DownSample) var aggregatorGen tsdb.AggregatorGenerator aggregatorGen, err = tsdbjson.NewAggregatorGenerator( parsedQueries[i].Aggregator.Type, parsedQueries[i].Aggregator.DownSample, parsedQueries[i].Aggregator.RateOptions, ) if err != nil { return } var series *tsdb.TaggedTimeSeriesSet series, err = tsdbimpl.Query( endpoints, parsedQueries[i].Metric, aggregatorGen, parsedQueries[i].Start, parsedQueries[i].End, &options) if err != nil { return } allSeries = append(allSeries, tsdbjson.NewTimeSeriesSlice(series)...) } if allSeries == nil { return make([]tsdbjson.TimeSeries, 0), nil } return allSeries, nil }
func TestAPI(t *testing.T) { alBuilder := datastructs.NewApplicationListBuilder() alBuilder.Add( 37, "AnApp", sources.ConnectorList{trisource.GetConnector()}) alBuilder.Add( 97, "AnotherApp", sources.ConnectorList{trisource.GetConnector()}) appList := alBuilder.Build() appStatus := datastructs.NewApplicationStatuses( appList, newStore( t, "TestAPI", 2, 100, 1.0, 10)) appStatus.MarkHostsActiveExclusively( 100.0, []string{"host1", "host2", "host3", "host4", "host5"}) endpointId, aStore := appStatus.EndpointIdByHostAndName( "host1", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 30.0, 510.0, 31.0, 520.0, 32.0, 530.0, 33.0, 540.0, 34.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host1", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 40.0, 510.0, 41.0, 520.0, 42.0, 530.0, 43.0, 540.0, 44.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host2", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 50.0, 510.0, 51.0, 520.0, 52.0, 530.0, 53.0, 540.0, 54.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host2", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 60.0, 510.0, 61.0, 520.0, 62.0, 530.0, 63.0, 540.0, 64.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 70.0, 510.0, 71.0, 520.0, 72.0, 530.0, 73.0, 540.0, 74.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 80.0, 510.0, 81.0, 520.0, 82.0, 530.0, 83.0, 540.0, 84.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host5", "AnApp") addValues(t, aStore, endpointId, "/bar", 700.0, 80.0, 800.0, 100.0) var taggedTimeSeriesSet *tsdb.TaggedTimeSeriesSet var err error if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 600.0, nil); err != nil { t.Fatal(err) } expected := &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {500.0, 55.5}, {520.0, 57.5}, {540.0, 59.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) if _, err = tsdbimpl.Query( appStatus, "/not there", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 600.0, nil); err != tsdbimpl.ErrNoSuchMetric { t.Error("Expected ErrNoSuchName") } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/bar", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 1000.0, nil); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/bar", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {700.0, 80.0}, {800.0, 100.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 501.0, 539.0, nil); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options := &tsdbimpl.QueryOptions{ GroupByHostName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host1", }, Values: tsdb.TimeSeries{ {500.0, 35.5}, {520.0, 37.5}, {540.0, 39.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", }, Values: tsdb.TimeSeries{ {500.0, 55.5}, {520.0, 57.5}, {540.0, 59.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", }, Values: tsdb.TimeSeries{ {500.0, 75.5}, {520.0, 77.5}, {540.0, 79.0}, }, }, }, GroupedByHostName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 700.0, 900.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", GroupedByHostName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64}, }, }, }, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host1", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 30.5}, {520.0, 32.5}, {540.0, 34.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host1", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 40.5}, {520.0, 42.5}, {540.0, 44.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 70.5}, {520.0, 72.5}, {540.0, 74.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 80.5}, {520.0, 82.5}, {540.0, 84.0}, }, }, }, GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 700.0, 900.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "AnApp" }), GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 70.5}, {520.0, 72.5}, {540.0, 74.0}, }, }, }, GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "AnApp" }), } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "No app" }), } if _, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != tsdbimpl.ErrNoSuchMetric { t.Error("Expected ErrNoSuchMetric") } }