diff --git a/public/app/plugins/datasource/influxdb/datasource.js b/public/app/plugins/datasource/influxdb/datasource.js index 56b01772c55..de7379d6367 100644 --- a/public/app/plugins/datasource/influxdb/datasource.js +++ b/public/app/plugins/datasource/influxdb/datasource.js @@ -69,8 +69,11 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) { var query = annotation.query.replace('$timeFilter', timeFilter); query = templateSrv.replace(query); - return this._seriesQuery(query).then(function(results) { - return new InfluxSeries({ seriesList: results, annotation: annotation }).getAnnotations(); + return this._seriesQuery(query).then(function(data) { + if (!data || !data.results || !data.results[0]) { + throw { message: 'No results in response from InfluxDB' }; + } + return new InfluxSeries({ series: data.results[0].series, annotation: annotation }).getAnnotations(); }); }; @@ -168,9 +171,11 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) { return deferred.promise; }; - function handleInfluxQueryResponse(alias, seriesList) { - var influxSeries = new InfluxSeries({ seriesList: seriesList, alias: alias }); - return influxSeries.getTimeSeries(); + function handleInfluxQueryResponse(alias, data) { + if (!data || !data.results || !data.results[0]) { + throw { message: 'No results in response from InfluxDB' }; + } + return new InfluxSeries({ series: data.results[0].series, alias: alias }).getTimeSeries(); } function getTimeFilter(options) { diff --git a/public/app/plugins/datasource/influxdb/influxSeries.js b/public/app/plugins/datasource/influxdb/influxSeries.js index cca01459fc4..45e4325c016 100644 --- a/public/app/plugins/datasource/influxdb/influxSeries.js +++ b/public/app/plugins/datasource/influxdb/influxSeries.js @@ -5,8 +5,7 @@ function (_) { 'use strict'; function InfluxSeries(options) { - this.seriesList = options.seriesList && options.seriesList.results && options.seriesList.results.length > 0 - ? options.seriesList.results[0].series || [] : []; + this.series = options.series; this.alias = options.alias; this.annotation = options.annotation; } @@ -17,23 +16,25 @@ function (_) { var output = []; var self = this; - console.log(self.seriesList); - if (self.seriesList.length === 0) { + if (self.series.length === 0) { return output; } - _.each(self.seriesList, function(series) { + _.each(self.series, function(series) { var datapoints = []; for (var i = 0; i < series.values.length; i++) { datapoints[i] = [series.values[i][1], new Date(series.values[i][0]).getTime()]; } var seriesName = series.name; - var tags = _.map(series.tags, function(value, key) { - return key + ': ' + value; - }); - if (tags.length > 0) { + if (self.alias) { + seriesName = self.alias; + } else if (series.tags) { + var tags = _.map(series.tags, function(value, key) { + return key + ': ' + value; + }); + seriesName = seriesName + ' {' + tags.join(', ') + '}'; } diff --git a/public/app/plugins/datasource/influxdb/partials/query.editor.html b/public/app/plugins/datasource/influxdb/partials/query.editor.html index 0881921078d..9a9fca802ea 100644 --- a/public/app/plugins/datasource/influxdb/partials/query.editor.html +++ b/public/app/plugins/datasource/influxdb/partials/query.editor.html @@ -141,14 +141,103 @@ +
+
+
+ +
+
+ +
+ +
+
+
+
+ +
+
Alias patterns
+
    +
  • $m = replaced with measurement name
  • +
  • $measurement = replaced with measurement name
  • +
  • $tag_hostname = replaced with the value of the hostname tag
  • +
  • You can also use [[tag_hostname]] pattern replacement syntax
  • +
+
+ +
+
Stacking and fill
+
    +
  • When stacking is enabled it important that points align
  • +
  • If there are missing points for one series it can cause gaps or missing bars
  • +
  • You must use fill(0), and select a group by time low limit
  • +
  • Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds
  • +
  • This will insert zeros for series that are missing measurements and will make stacking work properly
  • +
+
+ +
+
Group by time
+
    +
  • Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana
  • +
  • Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph
  • +
  • If you use fill(0) or fill(null) set a low limit for the auto group by time interval
  • +
  • The low limit can only be set in the group by time option below your queries
  • +
  • You set a low limit by adding a greater sign before the interval
  • +
  • Example: >60s if you write metrics to InfluxDB every 60 seconds
  • +
+
+ +
+ diff --git a/public/css/less/tightform.less b/public/css/less/tightform.less index 41630400cf7..5bd9cda8f43 100644 --- a/public/css/less/tightform.less +++ b/public/css/less/tightform.less @@ -23,7 +23,7 @@ .tight-form-container-no-item-borders { border: 1px solid @grafanaTargetBorder; - .tight-form, .tight-form-item { + .tight-form, .tight-form-item, [type=text].tight-form-input { border: none; } } diff --git a/public/test/specs/influxSeries-specs.js b/public/test/specs/influxSeries-specs.js index 47fb77b67b3..b68a3a95e8c 100644 --- a/public/test/specs/influxSeries-specs.js +++ b/public/test/specs/influxSeries-specs.js @@ -1,218 +1,57 @@ define([ - 'plugins/datasource/influxdb_08/influxSeries' + 'plugins/datasource/influxdb/influxSeries' ], function(InfluxSeries) { 'use strict'; describe('when generating timeseries from influxdb response', function() { describe('given two series', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - }, - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server2.cpu', - points: [[1402596000, 15, 1], [1402596001, 16, 2]] - } - ] - }); - - var result = series.getTimeSeries(); - - it('should generate two time series', function() { - expect(result.length).to.be(2); - expect(result[0].target).to.be('prod.server1.cpu.mean'); - expect(result[0].datapoints[0][0]).to.be(10); - expect(result[0].datapoints[0][1]).to.be(1402596000); - expect(result[0].datapoints[1][0]).to.be(12); - expect(result[0].datapoints[1][1]).to.be(1402596001); - - expect(result[1].target).to.be('prod.server2.cpu.mean'); - expect(result[1].datapoints[0][0]).to.be(15); - expect(result[1].datapoints[0][1]).to.be(1402596000); - expect(result[1].datapoints[1][0]).to.be(16); - expect(result[1].datapoints[1][1]).to.be(1402596001); - }); - - }); - - describe('given an alias format', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$s.testing' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('prod.server1.cpu.testing'); - }); - - }); - - describe('given an alias format with segment numbers', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'prod.server1.cpu', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$1.mean' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('server1.mean'); - }); - - }); - - describe('given an alias format and many segments', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'sequence_number'], - name: 'a0.a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12', - points: [[1402596000, 10, 1], [1402596001, 12, 2]] - } - ], - alias: '$5.$11.mean' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('a5.a11.mean'); - }); - - }); - - - describe('given an alias format with group by field', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'host'], - name: 'prod.cpu', - points: [[1402596000, 10, 'A']] - } - ], - groupByField: 'host', - alias: '$g.$1' - }); - - var result = series.getTimeSeries(); - - it('should generate correct series name', function() { - expect(result[0].target).to.be('A.cpu'); - }); - - }); - - describe('given group by column', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'mean', 'host'], - name: 'prod.cpu', - points: [ - [1402596000, 10, 'A'], - [1402596001, 11, 'A'], - [1402596000, 5, 'B'], - [1402596001, 6, 'B'], - ] - } - ], - groupByField: 'host' - }); - - var result = series.getTimeSeries(); - - it('should generate two time series', function() { - expect(result.length).to.be(2); - expect(result[0].target).to.be('prod.cpu.A'); - expect(result[0].datapoints[0][0]).to.be(10); - expect(result[0].datapoints[0][1]).to.be(1402596000); - expect(result[0].datapoints[1][0]).to.be(11); - expect(result[0].datapoints[1][1]).to.be(1402596001); - - expect(result[1].target).to.be('prod.cpu.B'); - expect(result[1].datapoints[0][0]).to.be(5); - expect(result[1].datapoints[0][1]).to.be(1402596000); - expect(result[1].datapoints[1][0]).to.be(6); - expect(result[1].datapoints[1][1]).to.be(1402596001); - }); - - }); - - }); - - describe("when creating annotations from influxdb response", function() { - describe('given column mapping for all columns', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'text', 'sequence_number', 'title', 'tags'], - name: 'events1', - points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']] - } - ], - annotation: { - query: 'select', - titleColumn: 'title', - tagsColumn: 'tags', - textColumn: 'text', + var options = { series: [ + { + name: 'cpu', + tags: {app: 'test'}, + columns: ['time', 'mean'], + values: [["2015-05-18T10:57:05Z", 10], ["2015-05-18T10:57:06Z", 12]] + }, + { + name: 'cpu', + tags: {app: 'test2'}, + columns: ['time', 'mean'], + values: [["2015-05-18T10:57:05Z", 15], ["2015-05-18T10:57:06Z", 16]] } + ]}; + + describe('and no alias', function() { + + it('should generate two time series', function() { + var series = new InfluxSeries(options); + var result = series.getTimeSeries(); + + expect(result.length).to.be(2); + expect(result[0].target).to.be('cpu {app: test}'); + expect(result[0].datapoints[0][0]).to.be(10); + expect(result[0].datapoints[0][1]).to.be(1431946625000); + expect(result[0].datapoints[1][0]).to.be(12); + expect(result[0].datapoints[1][1]).to.be(1431946626000); + + expect(result[1].target).to.be('cpu {app: test2}'); + expect(result[1].datapoints[0][0]).to.be(15); + expect(result[1].datapoints[0][1]).to.be(1431946625000); + expect(result[1].datapoints[1][0]).to.be(16); + expect(result[1].datapoints[1][1]).to.be(1431946626000); + }); }); - var result = series.getAnnotations(); + describe('and simple alias', function() { + it('should use alias', function() { + options.alias = 'new series'; + var series = new InfluxSeries(options); + var result = series.getTimeSeries(); + + expect(result[0].target).to.be('new series'); + }); - it(' should generate 2 annnotations ', function() { - expect(result.length).to.be(2); - expect(result[0].annotation.query).to.be('select'); - expect(result[0].title).to.be('Hello'); - expect(result[0].time).to.be(1402596000000); - expect(result[0].tags).to.be('B'); - expect(result[0].text).to.be('some text'); }); - - }); - - describe('given no column mapping', function() { - var series = new InfluxSeries({ - seriesList: [ - { - columns: ['time', 'text', 'sequence_number'], - name: 'events1', - points: [[1402596000000, 'some text', 1]] - } - ], - annotation: { query: 'select' } - }); - - var result = series.getAnnotations(); - - it('should generate 1 annnotation', function() { - expect(result.length).to.be(1); - expect(result[0].title).to.be('some text'); - expect(result[0].time).to.be(1402596000000); - expect(result[0].tags).to.be(undefined); - expect(result[0].text).to.be(undefined); - }); - }); }); diff --git a/public/test/specs/influxSeries08-specs.js b/public/test/specs/influxSeries08-specs.js new file mode 100644 index 00000000000..47fb77b67b3 --- /dev/null +++ b/public/test/specs/influxSeries08-specs.js @@ -0,0 +1,220 @@ +define([ + 'plugins/datasource/influxdb_08/influxSeries' +], function(InfluxSeries) { + 'use strict'; + + describe('when generating timeseries from influxdb response', function() { + + describe('given two series', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + }, + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server2.cpu', + points: [[1402596000, 15, 1], [1402596001, 16, 2]] + } + ] + }); + + var result = series.getTimeSeries(); + + it('should generate two time series', function() { + expect(result.length).to.be(2); + expect(result[0].target).to.be('prod.server1.cpu.mean'); + expect(result[0].datapoints[0][0]).to.be(10); + expect(result[0].datapoints[0][1]).to.be(1402596000); + expect(result[0].datapoints[1][0]).to.be(12); + expect(result[0].datapoints[1][1]).to.be(1402596001); + + expect(result[1].target).to.be('prod.server2.cpu.mean'); + expect(result[1].datapoints[0][0]).to.be(15); + expect(result[1].datapoints[0][1]).to.be(1402596000); + expect(result[1].datapoints[1][0]).to.be(16); + expect(result[1].datapoints[1][1]).to.be(1402596001); + }); + + }); + + describe('given an alias format', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$s.testing' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('prod.server1.cpu.testing'); + }); + + }); + + describe('given an alias format with segment numbers', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'prod.server1.cpu', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$1.mean' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('server1.mean'); + }); + + }); + + describe('given an alias format and many segments', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'sequence_number'], + name: 'a0.a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12', + points: [[1402596000, 10, 1], [1402596001, 12, 2]] + } + ], + alias: '$5.$11.mean' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('a5.a11.mean'); + }); + + }); + + + describe('given an alias format with group by field', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'host'], + name: 'prod.cpu', + points: [[1402596000, 10, 'A']] + } + ], + groupByField: 'host', + alias: '$g.$1' + }); + + var result = series.getTimeSeries(); + + it('should generate correct series name', function() { + expect(result[0].target).to.be('A.cpu'); + }); + + }); + + describe('given group by column', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'mean', 'host'], + name: 'prod.cpu', + points: [ + [1402596000, 10, 'A'], + [1402596001, 11, 'A'], + [1402596000, 5, 'B'], + [1402596001, 6, 'B'], + ] + } + ], + groupByField: 'host' + }); + + var result = series.getTimeSeries(); + + it('should generate two time series', function() { + expect(result.length).to.be(2); + expect(result[0].target).to.be('prod.cpu.A'); + expect(result[0].datapoints[0][0]).to.be(10); + expect(result[0].datapoints[0][1]).to.be(1402596000); + expect(result[0].datapoints[1][0]).to.be(11); + expect(result[0].datapoints[1][1]).to.be(1402596001); + + expect(result[1].target).to.be('prod.cpu.B'); + expect(result[1].datapoints[0][0]).to.be(5); + expect(result[1].datapoints[0][1]).to.be(1402596000); + expect(result[1].datapoints[1][0]).to.be(6); + expect(result[1].datapoints[1][1]).to.be(1402596001); + }); + + }); + + }); + + describe("when creating annotations from influxdb response", function() { + describe('given column mapping for all columns', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'text', 'sequence_number', 'title', 'tags'], + name: 'events1', + points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']] + } + ], + annotation: { + query: 'select', + titleColumn: 'title', + tagsColumn: 'tags', + textColumn: 'text', + } + }); + + var result = series.getAnnotations(); + + it(' should generate 2 annnotations ', function() { + expect(result.length).to.be(2); + expect(result[0].annotation.query).to.be('select'); + expect(result[0].title).to.be('Hello'); + expect(result[0].time).to.be(1402596000000); + expect(result[0].tags).to.be('B'); + expect(result[0].text).to.be('some text'); + }); + + }); + + describe('given no column mapping', function() { + var series = new InfluxSeries({ + seriesList: [ + { + columns: ['time', 'text', 'sequence_number'], + name: 'events1', + points: [[1402596000000, 'some text', 1]] + } + ], + annotation: { query: 'select' } + }); + + var result = series.getAnnotations(); + + it('should generate 1 annnotation', function() { + expect(result.length).to.be(1); + expect(result[0].title).to.be('some text'); + expect(result[0].time).to.be(1402596000000); + expect(result[0].tags).to.be(undefined); + expect(result[0].text).to.be(undefined); + }); + + }); + + }); + +}); diff --git a/public/test/test-main.js b/public/test/test-main.js index 86196069265..f064b81bab2 100644 --- a/public/test/test-main.js +++ b/public/test/test-main.js @@ -125,6 +125,7 @@ require([ 'specs/graphiteTargetCtrl-specs', 'specs/graphiteDatasource-specs', 'specs/influxSeries-specs', + 'specs/influxSeries08-specs', 'specs/influxQueryBuilder-specs', 'specs/influx09-querybuilder-specs', 'specs/influxdb-datasource-specs',