change: more work on changing default group by time interval to min interval setting

This commit is contained in:
Torkel Ödegaard 2017-09-01 15:57:02 +02:00
parent e8e1f1bc6d
commit 07e192ff47
12 changed files with 80 additions and 59 deletions

View File

@ -11,12 +11,10 @@ type DataSourcePlugin struct {
Annotations bool `json:"annotations"` Annotations bool `json:"annotations"`
Metrics bool `json:"metrics"` Metrics bool `json:"metrics"`
Alerting bool `json:"alerting"` Alerting bool `json:"alerting"`
MinInterval bool `json:"minInterval,omitempty"` QueryOptions map[string]bool `json:"queryOptions,omitempty"`
CacheTimeout bool `json:"cacheTimeout,omitempty"`
MaxDataPoints bool `json:"maxDataPoints,omitempty"`
BuiltIn bool `json:"builtIn,omitempty"` BuiltIn bool `json:"builtIn,omitempty"`
Mixed bool `json:"mixed,omitempty"` Mixed bool `json:"mixed,omitempty"`
HasHelp bool `json:"hasHelp,omitempty"` HasQueryHelp bool `json:"hasQueryHelp,omitempty"`
Routes []*AppPluginRoute `json:"-"` Routes []*AppPluginRoute `json:"-"`
} }
@ -31,12 +29,12 @@ func (p *DataSourcePlugin) Load(decoder *json.Decoder, pluginDir string) error {
} }
// look for help markdown // look for help markdown
helpPath := filepath.Join(p.PluginDir, "HELP.md") helpPath := filepath.Join(p.PluginDir, "QUERY_HELP.md")
if _, err := os.Stat(helpPath); os.IsNotExist(err) { if _, err := os.Stat(helpPath); os.IsNotExist(err) {
helpPath = filepath.Join(p.PluginDir, "help.md") helpPath = filepath.Join(p.PluginDir, "query_help.md")
} }
if _, err := os.Stat(helpPath); err == nil { if _, err := os.Stat(helpPath); err == nil {
p.HasHelp = true p.HasQueryHelp = true
} }
DataSources[p.Id] = p DataSources[p.Id] = p

View File

@ -163,22 +163,16 @@ function($, _) {
ms: 0.001 ms: 0.001
}; };
kbn.calculateInterval = function(range, resolution, userInterval) { kbn.calculateInterval = function(range, resolution, lowLimitInterval) {
var lowLimitMs = 1; // 1 millisecond default low limit var lowLimitMs = 1; // 1 millisecond default low limit
var intervalMs, lowLimitInterval; var intervalMs;
if (userInterval) { if (lowLimitInterval) {
if (userInterval[0] === '>') { if (lowLimitInterval[0] === '>') {
lowLimitInterval = userInterval.slice(1); lowLimitInterval = lowLimitInterval.slice(1);
}
lowLimitMs = kbn.interval_to_ms(lowLimitInterval); lowLimitMs = kbn.interval_to_ms(lowLimitInterval);
} }
else {
return {
intervalMs: kbn.interval_to_ms(userInterval),
interval: userInterval,
};
}
}
intervalMs = kbn.round_interval((range.to.valueOf() - range.from.valueOf()) / resolution); intervalMs = kbn.round_interval((range.to.valueOf() - range.from.valueOf()) / resolution);
if (lowLimitMs > intervalMs) { if (lowLimitMs > intervalMs) {

View File

@ -16,12 +16,10 @@ export class MetricsTabCtrl {
addQueryDropdown: any; addQueryDropdown: any;
queryTroubleshooterOpen: boolean; queryTroubleshooterOpen: boolean;
helpOpen: boolean; helpOpen: boolean;
hasHelp: boolean;
helpHtml: string;
hasMinInterval: boolean;
hasCacheTimeout: boolean;
hasMaxDataPoints: boolean;
optionsOpen: boolean; optionsOpen: boolean;
hasQueryHelp: boolean;
helpHtml: string;
queryOptions: any;
/** @ngInject */ /** @ngInject */
constructor($scope, private $sce, private datasourceSrv, private backendSrv, private $timeout) { constructor($scope, private $sce, private datasourceSrv, private backendSrv, private $timeout) {
@ -46,10 +44,8 @@ export class MetricsTabCtrl {
} }
updateDatasourceOptions() { updateDatasourceOptions() {
this.hasHelp = this.current.meta.hasHelp; this.hasQueryHelp = this.current.meta.hasQueryHelp;
this.hasMinInterval = this.current.meta.minInterval === true; this.queryOptions = this.current.meta.queryOptions;
this.hasCacheTimeout = this.current.meta.cacheTimeout === true;
this.hasMaxDataPoints = this.current.meta.maxDataPoints === true;
} }
getOptions(includeBuiltin) { getOptions(includeBuiltin) {
@ -89,7 +85,7 @@ export class MetricsTabCtrl {
this.queryTroubleshooterOpen = false; this.queryTroubleshooterOpen = false;
this.helpOpen = !this.helpOpen; this.helpOpen = !this.helpOpen;
this.backendSrv.get(`/api/plugins/${this.current.meta.id}/markdown/help`).then(res => { this.backendSrv.get(`/api/plugins/${this.current.meta.id}/markdown/query_help`).then(res => {
var md = new Remarkable(); var md = new Remarkable();
this.helpHtml = this.$sce.trustAsHtml(md.render(res)); this.helpHtml = this.$sce.trustAsHtml(md.render(res));
}); });

View File

@ -15,12 +15,12 @@
<div class="gf-form gf-form--grow"> <div class="gf-form gf-form--grow">
<label class="gf-form-label gf-form-label--grow"></label> <label class="gf-form-label gf-form-label--grow"></label>
</div> </div>
<div class="gf-form" ng-if="ctrl.hasHelp"> <div class="gf-form" ng-if="ctrl.queryOptions">
<a class="gf-form-label" ng-click="ctrl.toggleOptions()"> <a class="gf-form-label" ng-click="ctrl.toggleOptions()">
<i class="fa fa-fw fa-caret-right" ng-hide="ctrl.optionsOpen"></i><i class="fa fa-fw fa-caret-down" ng-show="ctrl.optionsOpen"></i>Options <i class="fa fa-fw fa-caret-right" ng-hide="ctrl.optionsOpen"></i><i class="fa fa-fw fa-caret-down" ng-show="ctrl.optionsOpen"></i>Options
</a> </a>
</div> </div>
<div class="gf-form" ng-if="ctrl.hasHelp"> <div class="gf-form" ng-if="ctrl.hasQueryHelp">
<button class="gf-form-label" ng-click="ctrl.toggleHelp()"> <button class="gf-form-label" ng-click="ctrl.toggleHelp()">
<i class="fa fa-fw fa-caret-right" ng-hide="ctrl.helpOpen"></i><i class="fa fa-fw fa-caret-down" ng-show="ctrl.helpOpen"></i>Help <i class="fa fa-fw fa-caret-right" ng-hide="ctrl.helpOpen"></i><i class="fa fa-fw fa-caret-down" ng-show="ctrl.helpOpen"></i>Help
</button> </button>
@ -33,8 +33,8 @@
</div> </div>
<div> <div>
<div class="" ng-if="ctrl.optionsOpen"> <div ng-if="ctrl.optionsOpen">
<div class="gf-form gf-form--flex-end" ng-if="ctrl.hasMinInterval"> <div class="gf-form gf-form--flex-end" ng-if="ctrl.queryOptions.minInterval">
<label class="gf-form-label">Min auto interval</label> <label class="gf-form-label">Min auto interval</label>
<input type="text" class="gf-form-input width-6" placeholder="1s" ng-model="ctrl.panel.interval" spellcheck="false" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" /> <input type="text" class="gf-form-input width-6" placeholder="1s" ng-model="ctrl.panel.interval" spellcheck="false" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" />
<info-popover mode="right-absolute"> <info-popover mode="right-absolute">
@ -43,7 +43,7 @@
string and <code>$__interval_ms</code> for numeric variable that can be used in math expressions. string and <code>$__interval_ms</code> for numeric variable that can be used in math expressions.
</info-popover> </info-popover>
</div> </div>
<div class="gf-form gf-form--flex-end" ng-if="ctrl.hasCacheTimeout"> <div class="gf-form gf-form--flex-end" ng-if="ctrl.queryOptions.cacheTimeout">
<label class="gf-form-label width-9">Cache timeout</label> <label class="gf-form-label width-9">Cache timeout</label>
<input type="text" class="gf-form-input width-6" placeholder="60" ng-model="ctrl.panel.cacheTimeout" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" spellcheck="false" /> <input type="text" class="gf-form-input width-6" placeholder="60" ng-model="ctrl.panel.cacheTimeout" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" spellcheck="false" />
<info-popover mode="right-absolute"> <info-popover mode="right-absolute">
@ -51,7 +51,7 @@
cache timeout. Specify a numeric value in seconds. cache timeout. Specify a numeric value in seconds.
</info-popover> </info-popover>
</div> </div>
<div class="gf-form gf-form--flex-end" ng-if="ctrl.hasMaxDataPoints"> <div class="gf-form gf-form--flex-end" ng-if="ctrl.queryOptions.maxDataPoints">
<label class="gf-form-label width-9">Max data points</label> <label class="gf-form-label width-9">Max data points</label>
<input type="text" class="gf-form-input width-6" placeholder="auto" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" ng-model="ctrl.panel.maxDataPoints" spellcheck="false" /> <input type="text" class="gf-form-input width-6" placeholder="auto" ng-model-onblur ng-change="ctrl.panelCtrl.refresh()" ng-model="ctrl.panel.maxDataPoints" spellcheck="false" />
<info-popover mode="right-absolute"> <info-popover mode="right-absolute">

View File

@ -54,7 +54,7 @@ export class IntervalVariable implements Variable {
this.options.unshift({ text: 'auto', value: '$__auto_interval' }); this.options.unshift({ text: 'auto', value: '$__auto_interval' });
} }
var res = kbn.calculateInterval(this.timeSrv.timeRange(), this.auto_count, (this.auto_min ? ">"+this.auto_min : null)); var res = kbn.calculateInterval(this.timeSrv.timeRange(), this.auto_count, this.auto_min);
this.templateSrv.setGrafanaVariable('$__auto_interval', res.interval); this.templateSrv.setGrafanaVariable('$__auto_interval', res.interval);
} }

View File

@ -25,13 +25,14 @@
<span class="gf-form-label width-9">Version</span> <span class="gf-form-label width-9">Version</span>
<select class="gf-form-input gf-size-auto" ng-model="ctrl.current.jsonData.esVersion" ng-options="f.value as f.name for f in ctrl.esVersions"></select> <select class="gf-form-input gf-size-auto" ng-model="ctrl.current.jsonData.esVersion" ng-options="f.value as f.name for f in ctrl.esVersions"></select>
</div> </div>
<div class="gf-form-inline">
</div>
<h3 class="page-heading">Default query settings</h3>
<div class="gf-form-group">
<div class="gf-form"> <div class="gf-form">
<span class="gf-form-label">Group by time interval</span> <span class="gf-form-label width-9">Min interval</span>
<input class="gf-form-input max-width-9" type="text" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="example: >10s"> <input type="text" class="gf-form-input width-6" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="10s"></input>
<info-popover mode="right-absolute">
A lower limit for the auto group by time interval. Recommended to be set to write frequency,
for example <code>1m</code> if your data is written every minute.
</info-popover>
</div>
</div> </div>
</div> </div>

View File

@ -10,8 +10,11 @@
"metrics": true, "metrics": true,
"alerting": true, "alerting": true,
"annotations": true, "annotations": true,
"queryOptions": {
"maxDataPoints": true, "maxDataPoints": true,
"cacheTimeout": true, "cacheTimeout": true
},
"info": { "info": {
"author": { "author": {

View File

@ -24,10 +24,14 @@
</div> </div>
<div class="gf-form-group"> <div class="gf-form-group">
<div class="gf-form max-width-21"> <div class="gf-form-inline">
<span class="gf-form-label">Default group by time</span> <div class="gf-form">
<input type="text" class="gf-form-input width-6" ng-model="ctrl.current.jsonData.timeInterval" <span class="gf-form-label">Min interval</span>
spellcheck='false' placeholder="example: >10s"></input> <input type="text" class="gf-form-input width-6" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="10s"></input>
<i class="fa fa-question-circle" bs-tooltip="'Set a low limit by having a greater sign: example: >10s'" data-placement="right"></i> <info-popover mode="right-absolute">
A lower limit for the auto group by time interval. Recommended to be set to write frequency,
for example <code>1m</code> if your data is written every minute.
</info-popover>
</div>
</div> </div>
</div> </div>

View File

@ -7,7 +7,10 @@
"metrics": true, "metrics": true,
"annotations": true, "annotations": true,
"alerting": true, "alerting": true,
"minInterval": true,
"queryOptions": {
"minInterval": true
},
"info": { "info": {
"author": { "author": {

View File

@ -0,0 +1,22 @@
#### Alias patterns
- replaced with measurement name
- $measurement = replaced with measurement name
- $1 - $9 = replaced with part of measurement name (if you separate your measurement name with dots)
- $col = replaced with column name
- $tag_exampletag = replaced with the value of the <i>exampletag</i> tag
- You can also use [[tag_exampletag]] pattern replacement syntax
#### Stacking and fill
- When stacking is enabled it is 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 &gt;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: &gt;60s if you write metrics to InfluxDB every 60 seconds

View File

@ -143,7 +143,7 @@ define([
expect(res.intervalMs).to.be(500); expect(res.intervalMs).to.be(500);
}); });
it('fixed user interval', function() { it('fixed user min interval', function() {
var range = {from: dateMath.parse('now-10m'), to: dateMath.parse('now')}; var range = {from: dateMath.parse('now-10m'), to: dateMath.parse('now')};
var res = kbn.calculateInterval(range, 1600, '10s'); var res = kbn.calculateInterval(range, 1600, '10s');
expect(res.interval).to.be('10s'); expect(res.interval).to.be('10s');