-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathopentsdb_connector.js
220 lines (186 loc) · 7.07 KB
/
opentsdb_connector.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
// Debugging output may be captured with console.log() and tableau.log()
$(function() {
$('#start_datetime').datetimepicker({ format: 'YYYY/MM/DD-HH:mm:ss' });
});
$(function() {
$('#end_datetime').datetimepicker({ format: 'YYYY/MM/DD-HH:mm:ss' });
});
function buildOpenTSDBUri(server, port, metric, startTime, endTime, tags) {
var tagSet = []; // Start with empty array
// Add "key=value" to the array for each tag in tags
Object.keys(tags).forEach( function(key) {
tagSet.push(key + "=" + tags[key])
})
// Turn into a comma-separated string
var tagString = "";
if ( tagSet.length > 0 ) {
tagString = "%7B" + tagSet.join(",") + "%7D";
}
// Build the final uri
var uri = "http://" + server + ":" + port + "/api/query?start=" + startTime
+ "&end=" + endTime + "&m=sum:rate:" + metric + tagString;
return uri;
}
function buildEtagsUri(server, port, metric, startTime, endTime) {
// Build the final uri
var etagsUri = "http://" + server + ":" + port + "/q?start=" + startTime
+ "&end=" + endTime + "&m=sum:rate:" + metric + "&json";
return etagsUri;
}
function buildTagsHtml(tags) {
// Build HTML from preamble, tags and postamble
var tagsHtml = '<div id="tags"><p>Tags:</p><div class="tags">' +
Object.keys(tags).sort(function(a, b) {
if (a == ' ') {
return 1;
} else {
return a - b;
}
}).map( function(t, i) {
return '<div class="tagLine">' +
'<input class="tagName" type="text" id="tagName' + i + '" value="' + t + '"/>' +
'<input class="tagVal" type="text" id="tagVal' + i + '" value="' + tags[t] + '"/>' +
'</div>';
}).join('') + '</div>';
return tagsHtml;
}
function getTagsFromHtml() {
// Gather current tag names/values from HTML (capture any fields modified by user)
var tags = {};
$(".tagName").map( function(i, el) {
tags[$("#tagName" + i).val()] = $("#tagVal" + i).val();
})
return tags;
}
(function() {
// TODO: Need to add more parameters here - e.g. tags (and their values), rate (true/false)
// http://127.0.0.1:4242/api/query?start=2015/10/28-05:48:10&end=2015/10/28-06:18:06&m=sum:rate:proc.net.tcp%7Bhost=*%7D&o=&yrange=%5B0:%5D&wxh=800x200&json
// http://127.0.0.1:4242/api/query?start=2015/10/28-05:45:00&end=2015/10/28-06:15:00&m=sum:rate:proc.stat.cpu
var myConnector = tableau.makeConnector();
myConnector.getTableData = function(lastRecordToken) {
var dataToReturn = [];
var hasMoreData = false;
var connectionData = JSON.parse(tableau.connectionData);
var metric = connectionData["metric"];
var startTime = connectionData["startTime"];
var endTime = connectionData["endTime"];
var tags = connectionData["tags"];
var server = connectionData["server"];
var port = connectionData["port"];
var metricUri = buildOpenTSDBUri(server, port, metric, startTime, endTime, tags);
var etagsUri = buildEtagsUri(server, port, metric, startTime, endTime);
var xhr = $.ajax({
url : metricUri,
dataType : 'json',
success : function(data) {
if (data != null) {
for (var int = 0; int < data.length; int++) {
var timeseries = data[int];
Object.keys(timeseries['dps']).forEach(function (key) {
var d_num = new Number(key);
var d;
// Check if timestamp is in milliseconds, if not multiply it by 1,000 to convert to milliseconds
if (d_num > 20000000000) {
d = new Date(d_num);
} else {
d = new Date(d_num*1000);
}
// TOOD: support relative times, e.g. 1h-ago, now
// timeStr should end up looking like this: yyyy-MM-dd HH:mm:ss.SSS
var timeStr = d.getFullYear()
+ "-" + ("0" + (d.getMonth() + 1)).substr(-2)
+ "-" + ("0" + d.getDate()).substr(-2)
+ " " + ("0" + d.getHours()).substr(-2)
+ ":" + ("0" + d.getMinutes()).substr(-2)
+ ":" + ("0" + d.getSeconds()).substr(-2);
// TODO: Test treatment of milliseconds with data having millisecond-granularity timestamps
if (d.getMilliseconds() != 0.0) {
timeStr += "." + String(d.getMilliseconds()).substr(1);
}
// Initialise entry with the static fields
var entry = {
'metric' : timeseries['metric'],
'timestamp': timeStr,
'value' : timeseries['dps'][key],
}
// Add tags
Object.keys(tags).forEach( function(t) {
entry[t] = timeseries['tags'][t];
});
dataToReturn.push(entry);
})
}
tableau.dataCallback(dataToReturn, lastRecordToken, false);
} else {
tableau.abortWithError("No results found for metric: " + metric);
}
},
error : function(xhr, ajaxOptions, thrownError) {
// If the connection fails, log the error and return an empty set
tableau.log("Connection error: " + xhr.responseText + "\n" + thrownError);
tableau.abortWithError("Error while trying to connect to OpenTSDB.");
}
});
};
myConnector.getColumnHeaders = function() {
var connectionData = JSON.parse(tableau.connectionData);
var tags = connectionData["tags"];
var fieldNames = ['metric', 'timestamp', 'value']; // Initialise fields with the fixed values
Object.keys(tags).forEach( function(t) { fieldNames.push(t); }); // Add tag names to fields
var fieldTypes = ['string', 'datetime', 'float']; // Initialise field types with fixed values
Object.keys(tags).forEach( function(t) { fieldTypes.push('string'); }); // Add tag types
tableau.headersCallback(fieldNames, fieldTypes);
}
tableau.registerConnector(myConnector);
})();
function updatePage() {
metric = $('#metric').val().trim();
startTime = $('#start_datetime').data('date');
endTime = $('#end_datetime').data('date');
tags = getTagsFromHtml();
// Ensure there's a blank tag name/value pair in tags, this allow a space for new tags to be entered
if ( ! $.inArray(' ', tags) > -1 ) {
tags[' '] = '';
}
var etagsUri = buildEtagsUri("127.0.0.1", "4242", metric, startTime, endTime);
jQuery.getJSON(etagsUri, function(data) {
// Compare current tag names to what is returned from etags, add missing tag names (with tag value
// initially set to empty)
data['etags'][0].forEach( function(tagName) {
if ( ! (tagName in tags) ) {
tags[tagName] = '';
}
})
$('#tags').replaceWith(buildTagsHtml(tags));
});
}
$(document).ready(function() {
var startTime;
var endTime;
var tags;
var metric;
// Define initial set of tags and insert into HTML
var tags = { 'host': '*' };
$('#tags').replaceWith(buildTagsHtml(tags));
$("#submitButton").click(function() {
metric = $('#metric').val().trim();
startTime = $('#start_datetime').data('date');
endTime = $('#end_datetime').data('date');
server = $('#server').val().trim();
port = $('#port').val().trim();
var tags = getTagsFromHtml();
// Remove any tags with blank names and/or values
delete tags[''];
for (var name in tags) {
if (tags[name] == '') {
delete tags[name];
}
}
if (metric) {
tableau.connectionName = "Data for metric: " + metric;
tableau.connectionData = JSON.stringify({'server': server, 'port': port, 'metric': metric,
'startTime': startTime, 'endTime': endTime, 'tags': tags});
tableau.submit();
}
});
});