mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
add prometheus annotation query
This commit is contained in:
parent
80e15dd754
commit
f8b05e0f42
@ -188,6 +188,58 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.annotationQuery = function(options) {
|
||||||
|
var annotation = options.annotation;
|
||||||
|
var expr = annotation.expr || '';
|
||||||
|
var tagKeys = annotation.tagKeys || '';
|
||||||
|
var titleFormat = annotation.titleFormat || '';
|
||||||
|
var textFormat = annotation.textFormat || '';
|
||||||
|
|
||||||
|
if (!expr) { return $q.when([]); }
|
||||||
|
|
||||||
|
var interpolated;
|
||||||
|
try {
|
||||||
|
interpolated = templateSrv.replace(expr);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
return $q.reject(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
var query = {
|
||||||
|
expr: interpolated,
|
||||||
|
step: '60s'
|
||||||
|
};
|
||||||
|
var start = getPrometheusTime(options.range.from, false);
|
||||||
|
var end = getPrometheusTime(options.range.to, true);
|
||||||
|
return this.performTimeSeriesQuery(query, start, end).then(function(results) {
|
||||||
|
var eventList = [];
|
||||||
|
tagKeys = tagKeys.split(',');
|
||||||
|
|
||||||
|
_.each(results.data.data.result, function(series) {
|
||||||
|
var tags = _.chain(series.metric)
|
||||||
|
.filter(function(v, k) {
|
||||||
|
return _.contains(tagKeys, k);
|
||||||
|
}).value();
|
||||||
|
|
||||||
|
_.each(series.values, function(value) {
|
||||||
|
if (value[1] === '1') {
|
||||||
|
var event = {
|
||||||
|
annotation: annotation,
|
||||||
|
time: Math.floor(value[0]) * 1000,
|
||||||
|
title: renderTemplate(titleFormat, series.metric),
|
||||||
|
tags: tags,
|
||||||
|
text: renderTemplate(textFormat, series.metric)
|
||||||
|
};
|
||||||
|
|
||||||
|
eventList.push(event);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return eventList;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
this.testDatasource = function() {
|
this.testDatasource = function() {
|
||||||
return this.metricFindQuery('metrics(.*)').then(function() {
|
return this.metricFindQuery('metrics(.*)').then(function() {
|
||||||
return { status: 'success', message: 'Data source is working', title: 'Success' };
|
return { status: 'success', message: 'Data source is working', title: 'Success' };
|
||||||
@ -240,22 +292,25 @@ export function PrometheusDatasource(instanceSettings, $q, backendSrv, templateS
|
|||||||
return getOriginalMetricName(labelData);
|
return getOriginalMetricName(labelData);
|
||||||
}
|
}
|
||||||
|
|
||||||
var originalSettings = _.templateSettings;
|
return renderTemplate(options.legendFormat, labelData) || '{}';
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderTemplate(format, data) {
|
||||||
_.templateSettings = {
|
_.templateSettings = {
|
||||||
interpolate: /\{\{(.+?)\}\}/g
|
interpolate: /\{\{(.+?)\}\}/g
|
||||||
};
|
};
|
||||||
|
|
||||||
var template = _.template(templateSrv.replace(options.legendFormat));
|
var template = _.template(templateSrv.replace(format));
|
||||||
var metricName;
|
var result;
|
||||||
try {
|
try {
|
||||||
metricName = template(labelData);
|
result = template(data);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
metricName = '{}';
|
result = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
_.templateSettings = originalSettings;
|
_.templateSettings = originalSettings;
|
||||||
|
|
||||||
return metricName;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOriginalMetricName(labelData) {
|
function getOriginalMetricName(labelData) {
|
||||||
|
@ -5,8 +5,13 @@ class PrometheusConfigCtrl {
|
|||||||
static templateUrl = 'public/app/plugins/datasource/prometheus/partials/config.html';
|
static templateUrl = 'public/app/plugins/datasource/prometheus/partials/config.html';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class PrometheusAnnotationsQueryCtrl {
|
||||||
|
static templateUrl = 'public/app/plugins/datasource/prometheus/partials/annotations.editor.html';
|
||||||
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
PrometheusDatasource as Datasource,
|
PrometheusDatasource as Datasource,
|
||||||
PrometheusQueryCtrl as QueryCtrl,
|
PrometheusQueryCtrl as QueryCtrl,
|
||||||
PrometheusConfigCtrl as ConfigCtrl
|
PrometheusConfigCtrl as ConfigCtrl,
|
||||||
|
PrometheusAnnotationsQueryCtrl as AnnotationsQueryCtrl,
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,28 @@
|
|||||||
|
<div class="editor-row">
|
||||||
|
<div class="section">
|
||||||
|
<h5>Search expression</h5>
|
||||||
|
<div class="editor-option">
|
||||||
|
<input type="text" class="span6" ng-model='currentAnnotation.expr' placeholder="ALERTS"></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="section">
|
||||||
|
<h5>Field formats</h5>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Title</label>
|
||||||
|
<input type="text" class="input-small" ng-model='currentAnnotation.titleFormat' placeholder="alertname"></input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Tags</label>
|
||||||
|
<input type="text" class="input-small" ng-model='currentAnnotation.tagKeys' placeholder="label1,label2"></input>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Text</label>
|
||||||
|
<input type="text" class="input-small" ng-model='currentAnnotation.textFormat' placeholder="instance"></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -3,5 +3,6 @@
|
|||||||
"name": "Prometheus",
|
"name": "Prometheus",
|
||||||
"id": "prometheus",
|
"id": "prometheus",
|
||||||
|
|
||||||
"metrics": true
|
"metrics": true,
|
||||||
|
"annotations": true
|
||||||
}
|
}
|
||||||
|
@ -157,4 +157,39 @@ describe('PrometheusDatasource', function() {
|
|||||||
expect(results.length).to.be(3);
|
expect(results.length).to.be(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('When performing annotationQuery', function() {
|
||||||
|
var results;
|
||||||
|
var urlExpected = 'proxied/api/v1/query_range?query=' +
|
||||||
|
encodeURIComponent('ALERTS{alertstate="firing"}') +
|
||||||
|
'&start=1443438675&end=1443460275&step=60s';
|
||||||
|
var annotation = {
|
||||||
|
expr: 'ALERTS{alertstate="firing"}',
|
||||||
|
tagKeys: 'job',
|
||||||
|
titleFormat: '{{alertname}}',
|
||||||
|
textFormat: '{{instance}}'
|
||||||
|
};
|
||||||
|
var response = {
|
||||||
|
status: "success",
|
||||||
|
data: {
|
||||||
|
resultType: "matrix",
|
||||||
|
result: [{
|
||||||
|
metric: {"__name__": "ALERTS", alertname: "InstanceDown", alertstate: "firing", instance: "testinstance", job: "testjob"},
|
||||||
|
values: [[1443454528, "1"]]
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
beforeEach(function() {
|
||||||
|
ctx.$httpBackend.expect('GET', urlExpected).respond(response);
|
||||||
|
ctx.ds.annotationQuery(annotation, {from: moment(1443438674760), to: moment(1443460274760)}).then(function(data) { results = data; });
|
||||||
|
ctx.$httpBackend.flush();
|
||||||
|
});
|
||||||
|
it('should return annotation list', function() {
|
||||||
|
ctx.$rootScope.$apply();
|
||||||
|
expect(results.length).to.be(1);
|
||||||
|
expect(results[0].tags).to.contain('testjob');
|
||||||
|
expect(results[0].title).to.be('InstanceDown');
|
||||||
|
expect(results[0].text).to.be('testinstance');
|
||||||
|
expect(results[0].time).to.be(1443454528 * 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user