Commit f0f4c8cc by Torkel Ödegaard

A lot more work on annotations (#44, #8). Graphite events is working, editing,…

A lot more work on annotations (#44, #8). Graphite events is working, editing, icon size, color and vertical line toggle/options working. To sleepy now...
parent 47db82d6
...@@ -183,6 +183,16 @@ function (angular, $, config, _) { ...@@ -183,6 +183,16 @@ function (angular, $, config, _) {
return _.isNull(_error) ? data : _error[1]; return _.isNull(_error) ? data : _error[1];
}; };
$scope.colors = [
"#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1
"#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2
"#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3
"#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", //4
"#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", //5
"#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", //6
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7
];
$scope.init(); $scope.init();
}); });
}); });
\ No newline at end of file
...@@ -20,7 +20,6 @@ function (angular, $, kbn, moment, _) { ...@@ -20,7 +20,6 @@ function (angular, $, kbn, moment, _) {
scope.$on('refresh',function() { scope.$on('refresh',function() {
if (scope.otherPanelInFullscreenMode()) { return; } if (scope.otherPanelInFullscreenMode()) { return; }
scope.get_data(); scope.get_data();
}); });
...@@ -121,6 +120,7 @@ function (angular, $, kbn, moment, _) { ...@@ -121,6 +120,7 @@ function (angular, $, kbn, moment, _) {
ticks: elem.width()/100 ticks: elem.width()/100
}, },
grid: { grid: {
markings: [],
backgroundColor: null, backgroundColor: null,
borderWidth: 0, borderWidth: 0,
hoverable: true, hoverable: true,
...@@ -191,7 +191,6 @@ function (angular, $, kbn, moment, _) { ...@@ -191,7 +191,6 @@ function (angular, $, kbn, moment, _) {
function addGridThresholds(options, panel) { function addGridThresholds(options, panel) {
if (panel.grid.threshold1) { if (panel.grid.threshold1) {
var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null); var limit1 = panel.grid.thresholdLine ? panel.grid.threshold1 : (panel.grid.threshold2 || null);
options.grid.markings = [];
options.grid.markings.push({ options.grid.markings.push({
yaxis: { from: panel.grid.threshold1, to: limit1 }, yaxis: { from: panel.grid.threshold1, to: limit1 },
color: panel.grid.threshold1Color color: panel.grid.threshold1Color
...@@ -217,20 +216,33 @@ function (angular, $, kbn, moment, _) { ...@@ -217,20 +216,33 @@ function (angular, $, kbn, moment, _) {
return; return;
} }
options.events = { var types = {};
levels: 1,
data: data.annotations, _.each(data.annotations, function(event) {
types: { if (!types[event.annotation.name]) {
'annotation': { types[event.annotation.name] = {
level: 1, level: _.keys(types).length + 1,
icon: { icon: {
icon: "icon-tag icon-flip-vertical", icon: "icon-chevron-up",
size: 20, size: event.annotation.iconSize,
color: "#222", color: event.annotation.iconColor,
outline: "#bbb"
} }
} };
} }
if (event.annotation.showLine) {
options.grid.markings.push({
color: event.annotation.lineColor,
lineWidth: 1,
xaxis: { from: event.min, to: event.max }
});
}
});
options.events = {
levels: _.keys(types).length + 1,
data: data.annotations,
types: types
}; };
} }
......
...@@ -2,19 +2,20 @@ ...@@ -2,19 +2,20 @@
<div class="pull-right editor-title">Annotations</div> <div class="pull-right editor-title">Annotations</div>
<div class="editor-row"> <div class="editor-row">
<table class="table table-striped annotation-editor-table"> <table class="table table-striped annotation-editor-table" style="width: 700px">
<thead> <thead>
<th width="1%"></th>
<th width="1%">Type</th>
<th width="90%">Name</th> <th width="90%">Name</th>
<th width="1%"></th> <th width="1%"></th>
<th width="1%"></th> <th width="1%"></th>
<th width="1%"></th> <th width="1%"></th>
</thead> </thead>
<tr ng-repeat="annotation in panel.annotations"> <tr ng-repeat="annotation in panel.annotations">
<td><a ng-click="edit(annotation)"><i class="icon-pencil" /></a></td> <td>
<td>{{annotation.type}}</td> <a ng-click="edit(annotation)" bs-tooltip="'Click to edit'">
<td>{{annotation.name}}</td> <i class="icon-cog"></i>
{{annotation.name}}
</a>
</td>
<td><i ng-click="_.move(panel.annotations,$index,$index-1)" ng-hide="$first" class="pointer icon-arrow-up"></i></td> <td><i ng-click="_.move(panel.annotations,$index,$index-1)" ng-hide="$first" class="pointer icon-arrow-up"></i></td>
<td><i ng-click="_.move(panel.annotations,$index,$index+1)" ng-hide="$last" class="pointer icon-arrow-down"></i></td> <td><i ng-click="_.move(panel.annotations,$index,$index+1)" ng-hide="$last" class="pointer icon-arrow-down"></i></td>
<td><i ng-click="panel.annotations = _.without(panel.annotations, annotation)" class="pointer icon-remove"></i></td> <td><i ng-click="panel.annotations = _.without(panel.annotations, annotation)" class="pointer icon-remove"></i></td>
...@@ -34,6 +35,22 @@ ...@@ -34,6 +35,22 @@
<label class="small">Type</label> <label class="small">Type</label>
<select ng-model="currentAnnnotation.type" ng-options="f for f in ['graphite metric', 'graphite events']"></select> <select ng-model="currentAnnnotation.type" ng-options="f for f in ['graphite metric', 'graphite events']"></select>
</div> </div>
<div class="editor-option">
<label class="small">Icon color</label>
<spectrum-picker ng-model="currentAnnnotation.iconColor"></spectrum-picker>
</div>
<div class="editor-option">
<label class="small">Icon size</label>
<select class="input-mini" ng-model="currentAnnnotation.iconSize" ng-options="f for f in [7,8,9,10,13,15,17,20,25,30]"></select>
</div>
<div class="editor-option">
<label class="small">Grid line</label>
<input type="checkbox" ng-model="currentAnnnotation.showLine" ng-checked="currentAnnnotation.showLine">
</div>
<div class="editor-option">
<label class="small">Line color</label>
<spectrum-picker ng-model="currentAnnnotation.lineColor"></spectrum-picker>
</div>
</div> </div>
<div class="editor-row" ng-if="currentAnnnotation.type === 'graphite metric'"> <div class="editor-row" ng-if="currentAnnnotation.type === 'graphite metric'">
...@@ -55,5 +72,5 @@ ...@@ -55,5 +72,5 @@
<div class="modal-footer"> <div class="modal-footer">
<button ng-show="currentIsNew" type="button" class="btn btn-success" ng-click="add()">Add annotation</button> <button ng-show="currentIsNew" type="button" class="btn btn-success" ng-click="add()">Add annotation</button>
<button ng-show="!currentIsNew" type="button" class="btn btn-success" ng-click="update()">Update</button> <button ng-show="!currentIsNew" type="button" class="btn btn-success" ng-click="update()">Update</button>
<button type="button" class="btn btn-danger" ng-click="close_edit();dismiss()">Close</button> <button type="button" class="btn btn-danger" ng-click="close_edit();dismiss();dashboard.refresh();">Close</button>
</div> </div>
\ No newline at end of file
...@@ -28,7 +28,12 @@ function (angular, app, _) { ...@@ -28,7 +28,12 @@ function (angular, app, _) {
var annotationDefaults = { var annotationDefaults = {
name: '', name: '',
type: 'graphite metric' type: 'graphite metric',
showLine: true,
iconColor: '#E24D42',
lineColor: '#E24D42',
iconSize: 15,
enable: true
}; };
_.defaults($scope.panel,_d); _.defaults($scope.panel,_d);
......
...@@ -266,16 +266,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) { ...@@ -266,16 +266,6 @@ function (angular, app, $, _, kbn, moment, timeSeries) {
} }
}; };
$scope.colors = [
"#7EB26D","#EAB839","#6ED0E0","#EF843C","#E24D42","#1F78C1","#BA43A9","#705DA0", //1
"#508642","#CCA300","#447EBC","#C15C17","#890F02","#0A437C","#6D1F62","#584477", //2
"#B7DBAB","#F4D598","#70DBED","#F9BA8F","#F29191","#82B5D8","#E5A8E2","#AEA2E0", //3
"#629E51","#E5AC0E","#64B0C8","#E0752D","#BF1B00","#0A50A1","#962D82","#614D93", //4
"#9AC48A","#F2C96D","#65C5DB","#F9934E","#EA6460","#5195CE","#D683CE","#806EB7", //5
"#3F6833","#967302","#2F575E","#99440A","#58140C","#052B51","#511749","#3F2B5B", //6
"#E0F9D7","#FCEACA","#CFFAFF","#F9E2D2","#FCE2DE","#BADFF4","#F9D9F9","#DEDAF7" //7
];
/** /**
* Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies * Fetch the data for a chunk of a queries results. Multiple segments occur when several indicies
* need to be consulted (like timestamped logstash indicies) * need to be consulted (like timestamped logstash indicies)
......
...@@ -35,6 +35,45 @@ define([ ...@@ -35,6 +35,45 @@ define([
return promiseCached; return promiseCached;
} }
var graphiteMetrics = this.getGraphiteMetrics(rangeUnparsed);
var graphiteEvents = this.getGraphiteEvents(rangeUnparsed);
promiseCached = $q.all([graphiteMetrics, graphiteEvents])
.then(function(allAnnotations) {
var nonNull = _.filter(allAnnotations, function(value) { return value !== null; });
return _.flatten(nonNull);
});
return promiseCached;
};
this.getGraphiteEvents = function(rangeUnparsed) {
var annotations = _.where(annotationPanel.annotations, { type: 'graphite events', enable: true });
var tags = _.pluck(annotations, 'tags');
if (tags.length === 0) {
return $q.when(null);
}
var eventsQuery = {
range: rangeUnparsed,
tags: tags.join(' '),
};
return datasourceSrv.default.events(eventsQuery)
.then(function(results) {
var list = [];
_.each(results.data, function (event) {
list.push(createAnnotation(annotations[0], event.when * 1000, event.what, event.tags, event.data));
});
return list;
})
.then(null, function() {
alertSrv.set('Annotations','Could not fetch annotations','error');
});
};
this.getGraphiteMetrics = function(rangeUnparsed) {
var graphiteAnnotations = _.where(annotationPanel.annotations, { type: 'graphite metric', enable: true }); var graphiteAnnotations = _.where(annotationPanel.annotations, { type: 'graphite metric', enable: true });
var graphiteTargets = _.map(graphiteAnnotations, function(annotation) { var graphiteTargets = _.map(graphiteAnnotations, function(annotation) {
return { target: annotation.target }; return { target: annotation.target };
...@@ -51,7 +90,7 @@ define([ ...@@ -51,7 +90,7 @@ define([
maxDataPoints: 100 maxDataPoints: 100
}; };
promiseCached = datasourceSrv.default.query(graphiteQuery) return datasourceSrv.default.query(graphiteQuery)
.then(function(results) { .then(function(results) {
return _.reduce(results.data, function(list, target) { return _.reduce(results.data, function(list, target) {
_.each(target.datapoints, function (values) { _.each(target.datapoints, function (values) {
...@@ -59,16 +98,7 @@ define([ ...@@ -59,16 +98,7 @@ define([
return; return;
} }
list.push(createAnnotation(graphiteAnnotations[0], values[1] * 1000, target.target));
list.push({
min: values[1] * 1000,
max: values[1] * 1000,
eventType: "annotation",
title: null,
description: "<small>" + target.target + "</small><br>"+
moment(values[1] * 1000).format('YYYY-MM-DD HH:mm:ss'),
score: 1
});
}); });
return list; return list;
...@@ -77,10 +107,30 @@ define([ ...@@ -77,10 +107,30 @@ define([
.then(null, function() { .then(null, function() {
alertSrv.set('Annotations','Could not fetch annotations','error'); alertSrv.set('Annotations','Could not fetch annotations','error');
}); });
return promiseCached;
}; };
function createAnnotation(annotation, time, description, tags, data) {
var tooltip = "<small><b>" + description + "</b><br/>";
if (tags) {
tooltip += (tags || '') + '<br/>';
}
tooltip += '<i>' + moment(time).format('YYYY-MM-DD HH:mm:ss') + '</i><br/>';
if (data) {
tooltip += data;
}
tooltip += "</small>";
return {
annotation: annotation,
min: time,
max: time,
eventType: annotation.name,
title: null,
description: tooltip,
score: 1
};
}
// Now init // Now init
this.init(); this.init();
}); });
......
...@@ -37,7 +37,6 @@ function (angular, _, $, config, kbn, moment) { ...@@ -37,7 +37,6 @@ function (angular, _, $, config, kbn, moment) {
return this.doGraphiteRequest({ return this.doGraphiteRequest({
method: 'POST', method: 'POST',
url: '/render', url: '/render',
datasource: options.datasource,
data: params.join('&'), data: params.join('&'),
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
...@@ -49,6 +48,23 @@ function (angular, _, $, config, kbn, moment) { ...@@ -49,6 +48,23 @@ function (angular, _, $, config, kbn, moment) {
} }
}; };
GraphiteDatasource.prototype.events = function(options) {
try {
var tags = '';
if (options.tags) {
tags = '&tags=' + options.tags;
}
return this.doGraphiteRequest({
method: 'GET',
url: '/events/get_data?from=' + this.translateTime(options.range.from) + '&until=' + this.translateTime(options.range.to) + tags,
});
}
catch(err) {
return this.$q.reject(err);
}
};
GraphiteDatasource.prototype.translateTime = function(date) { GraphiteDatasource.prototype.translateTime = function(date) {
if (_.isString(date)) { if (_.isString(date)) {
if (date === 'now') { if (date === 'now') {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -437,4 +437,17 @@ input[type=text].func-param { ...@@ -437,4 +437,17 @@ input[type=text].func-param {
border: none; border: none;
} }
.sp-dd {
display: none;
}
.sp-preview {
position: relative;
width: 15px;
height: 15px;
border: none;
margin-right: 5px;
float: left;
z-index: 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment