Prepare for using Grafana annotations with tags (coming in Grafana 5.4) (#2152)
* Prepare for using Grafana annotations with tags (coming in Grafana 5.4) #1826 * push the cli when 5.4 Grafana is released
This commit is contained in:
parent
a9073bf3fd
commit
3e24d65466
|
|
@ -8,6 +8,7 @@ let yargs = require('yargs'),
|
|||
cliUtil = require('./util'),
|
||||
fs = require('fs'),
|
||||
set = require('lodash.set'),
|
||||
// grafanaConfig = require('../plugins/grafana/index').config,
|
||||
graphiteConfig = require('../plugins/graphite/index').config,
|
||||
influxdbConfig = require('../plugins/influxdb/index').config,
|
||||
browsertimeConfig = require('../plugins/browsertime/index').config,
|
||||
|
|
@ -394,6 +395,20 @@ module.exports.parseCommandLine = function parseCommandLine() {
|
|||
describe: 'The max number of pages to test. Default is no limit.',
|
||||
group: 'Crawler'
|
||||
})
|
||||
/**
|
||||
Grafana cli option
|
||||
*/
|
||||
/** Activate them when Grafana 5.4 is live
|
||||
.option('grafana.host', {
|
||||
describe: 'The Grafana host used when sending annotations.',
|
||||
group: 'Grafana'
|
||||
})
|
||||
.option('grafana.port', {
|
||||
default: grafanaConfig.port,
|
||||
describe: 'The Grafana port used when sending annotations to Grafana.',
|
||||
group: 'Grafana'
|
||||
})
|
||||
*/
|
||||
/**
|
||||
Graphite cli option
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
'use strict';
|
||||
const sendAnnotations = require('./send-annotation');
|
||||
const throwIfMissing = require('../../support/util').throwIfMissing;
|
||||
const defaultConfig = {
|
||||
port: 80
|
||||
};
|
||||
module.exports = {
|
||||
open(context, options) {
|
||||
throwIfMissing(options.grafana, ['host', 'port'], 'grafana');
|
||||
this.options = options;
|
||||
this.timestamp = context.timestamp;
|
||||
this.resultUrls = context.resultUrls;
|
||||
this.annotationType = 'webpagetest.pageSummary';
|
||||
this.tsdbType = 'graphite';
|
||||
this.make = context.messageMaker('grafana').make;
|
||||
},
|
||||
processMessage(message, queue) {
|
||||
// First catch if we are running Browsertime and/or WebPageTest
|
||||
if (message.type === 'browsertime.setup') {
|
||||
this.annotationType = 'browsertime.pageSummary';
|
||||
} else if (message.type === 'sitespeedio.setup') {
|
||||
// Let other plugins know that the Grafana plugin is alive
|
||||
queue.postMessage(this.make('grafana.setup'));
|
||||
} else if (message.type === 'influxdb.setup') {
|
||||
// Default we use Graphite config, else use influxdb
|
||||
this.tsdbType = 'influxdb';
|
||||
} else if (message.type === 'browsertime.config') {
|
||||
if (message.data.screenshot) {
|
||||
this.useScreenshots = message.data.screenshot;
|
||||
this.screenshotType = message.data.screenshotType;
|
||||
}
|
||||
} else if (
|
||||
message.type === this.annotationType &&
|
||||
this.resultUrls.hasBaseUrl()
|
||||
) {
|
||||
const absolutePagePath = this.resultUrls.absoluteSummaryPageUrl(
|
||||
message.url
|
||||
);
|
||||
return sendAnnotations.send(
|
||||
message.url,
|
||||
message.group,
|
||||
absolutePagePath,
|
||||
this.screenShotsEnabledInBrowsertime,
|
||||
this.screenshotType,
|
||||
this.timestamp,
|
||||
this.tsdbType,
|
||||
this.options
|
||||
);
|
||||
}
|
||||
},
|
||||
config: defaultConfig
|
||||
};
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
'use strict';
|
||||
const http = require('http');
|
||||
const https = require('https');
|
||||
const log = require('intel').getLogger('sitespeedio.plugin.grafana');
|
||||
const Promise = require('bluebird');
|
||||
const tsdbUtil = require('../../support/tsdbUtil');
|
||||
const annotationsHelper = require('../../support/annotationsHelper');
|
||||
const util = require('../../support/util');
|
||||
|
||||
module.exports = {
|
||||
send(
|
||||
url,
|
||||
group,
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
time,
|
||||
tsdbType,
|
||||
options
|
||||
) {
|
||||
// The tags make it possible for the dashboard to use the
|
||||
// templates to choose which annotations that will be showed.
|
||||
// That's why we need to send tags that matches the template
|
||||
// variables in Grafana.
|
||||
const connectivity = tsdbUtil.getConnectivity(options);
|
||||
const browser = options.browser;
|
||||
// Hmm, here we have hardcoded Graphite ...
|
||||
const namespace = options.graphite.namespace.split('.');
|
||||
const urlAndGroup = tsdbUtil
|
||||
.getURLAndGroup(
|
||||
options,
|
||||
group,
|
||||
url,
|
||||
tsdbType === 'graphite'
|
||||
? options.graphite.includeQueryParams
|
||||
: options.influxdb.includeQueryParams
|
||||
)
|
||||
.split('.');
|
||||
|
||||
const tags = [
|
||||
connectivity,
|
||||
browser,
|
||||
namespace[0],
|
||||
namespace[1],
|
||||
urlAndGroup[0],
|
||||
urlAndGroup[1]
|
||||
];
|
||||
const extraTags = util.toArray(options.grafana.annotationTag);
|
||||
// We got some extra tag(s) from the user, let us add them to the annotation
|
||||
if (extraTags.length > 0) {
|
||||
tags.push(...extraTags);
|
||||
}
|
||||
|
||||
const tagsArray = annotationsHelper.getTagsAsArray(tags);
|
||||
|
||||
const message = annotationsHelper.getAnnotationMessage(
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
options
|
||||
);
|
||||
const timestamp = Math.round(time.valueOf() / 1000);
|
||||
const s = options.browsertime.iterations > 1 ? 's' : '';
|
||||
const postData = `{"what": "${
|
||||
options.browsertime.iterations
|
||||
} run${s}", "tags": ${tagsArray}, "data": "${message}", "when": ${timestamp}}`;
|
||||
const postOptions = {
|
||||
hostname: options.grafana.host,
|
||||
port: options.grafana.port,
|
||||
path: '/api/annotations/graphite',
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Content-Length': Buffer.byteLength(postData)
|
||||
}
|
||||
};
|
||||
// If Grafana is behind auth, use it!
|
||||
if (options.grafana.auth) {
|
||||
postOptions.headers.Authorization = 'Bearer ' + options.grafana.auth;
|
||||
}
|
||||
log.verbose('Send annotation to Grafana: %j', postData);
|
||||
return new Promise((resolve, reject) => {
|
||||
// not perfect but maybe work for us
|
||||
const lib = options.grafana.port === 443 ? https : http;
|
||||
const req = lib.request(postOptions, res => {
|
||||
if (res.statusCode !== 200) {
|
||||
const e = new Error(
|
||||
`Got ${res.statusCode} from Grafana when sending annotation`
|
||||
);
|
||||
log.warn(e.message);
|
||||
reject(e);
|
||||
} else {
|
||||
res.setEncoding('utf8');
|
||||
log.debug('Sent annotation to Grafana');
|
||||
resolve();
|
||||
}
|
||||
});
|
||||
req.on('error', err => {
|
||||
log.error('Got error from Grafana when sending annotation', err);
|
||||
reject(err);
|
||||
});
|
||||
req.write(postData);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -41,9 +41,11 @@ module.exports = {
|
|||
this.timestamp = context.timestamp;
|
||||
this.resultUrls = context.resultUrls;
|
||||
this.annotationType = 'webpagetest.pageSummary';
|
||||
this.make = context.messageMaker('graphite').make;
|
||||
this.sendAnnotation = true;
|
||||
},
|
||||
|
||||
processMessage(message) {
|
||||
processMessage(message, queue) {
|
||||
// First catch if we are running Browsertime and/or WebPageTest
|
||||
if (message.type === 'browsertime.setup') {
|
||||
this.annotationType = 'browsertime.pageSummary';
|
||||
|
|
@ -52,6 +54,11 @@ module.exports = {
|
|||
this.useScreenshots = message.data.screenshot;
|
||||
this.screenshotType = message.data.screenshotType;
|
||||
}
|
||||
} else if (message.type === 'sitespeedio.setup') {
|
||||
// Let other plugins know that the Graphite plugin is alive
|
||||
queue.postMessage(this.make('graphite.setup'));
|
||||
} else if (message.type === 'grafana.setup') {
|
||||
this.sendAnnotation = false;
|
||||
}
|
||||
|
||||
const filterRegistry = this.filterRegistry;
|
||||
|
|
@ -89,30 +96,21 @@ module.exports = {
|
|||
// when we configured a base url
|
||||
if (
|
||||
message.type === this.annotationType &&
|
||||
this.resultUrls.hasBaseUrl()
|
||||
this.resultUrls.hasBaseUrl() &&
|
||||
this.sendAnnotation
|
||||
) {
|
||||
const resultPageUrl = this.resultUrls.absoluteSummaryPagePath(
|
||||
const absolutePagePath = this.resultUrls.absoluteSummaryPagePath(
|
||||
message.url
|
||||
);
|
||||
let screenshotPath;
|
||||
if (this.useScreenshots) {
|
||||
screenshotPath =
|
||||
resultPageUrl + 'data/screenshots/1.' + this.screenshotType;
|
||||
}
|
||||
|
||||
const harPath =
|
||||
resultPageUrl +
|
||||
'data/browsertime.har' +
|
||||
(this.options.gzipHAR ? '.gz' : '');
|
||||
|
||||
return sendAnnotations.send(
|
||||
this.options,
|
||||
message.group,
|
||||
message.url,
|
||||
resultPageUrl + 'index.html',
|
||||
screenshotPath,
|
||||
harPath,
|
||||
this.timestamp
|
||||
message.group,
|
||||
absolutePagePath,
|
||||
this.useScreenshots,
|
||||
this.screenshotType,
|
||||
this.timestamp,
|
||||
this.options
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4,10 +4,19 @@ const https = require('https');
|
|||
const log = require('intel').getLogger('sitespeedio.plugin.graphite');
|
||||
const Promise = require('bluebird');
|
||||
const graphiteUtil = require('../../support/tsdbUtil');
|
||||
const annotationsHelper = require('../../support/annotationsHelper');
|
||||
const util = require('../../support/util');
|
||||
|
||||
module.exports = {
|
||||
send(options, group, url, resultPageUrl, screenshotPath, harPath, time) {
|
||||
send(
|
||||
url,
|
||||
group,
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
time,
|
||||
options
|
||||
) {
|
||||
// The tags make it possible for the dashboard to use the
|
||||
// templates to choose which annotations that will be showed.
|
||||
// That's why we need to send tags that matches the template
|
||||
|
|
@ -31,32 +40,18 @@ module.exports = {
|
|||
if (extraTags.length > 0) {
|
||||
tags.push(...extraTags);
|
||||
}
|
||||
let tagsString = `"`;
|
||||
let tagsArray = '[';
|
||||
for (let myTag of tags) {
|
||||
tagsString += myTag + ',';
|
||||
tagsArray += '"' + myTag + '",';
|
||||
}
|
||||
tagsString = tagsString.substring(0, tagsString.length - 1);
|
||||
tagsArray = tagsArray.substring(0, tagsArray.length - 1);
|
||||
tagsString += '"';
|
||||
tagsArray += ']';
|
||||
const theTags = options.graphite.arrayTags
|
||||
? annotationsHelper.getTagsAsArray(tags)
|
||||
: annotationsHelper.getTagsAsString(tags);
|
||||
|
||||
const s = options.browsertime.iterations > 1 ? 's' : '';
|
||||
const screenshotSize = options.mobile ? 'height=200px' : 'width=100%';
|
||||
let message =
|
||||
screenshotPath &&
|
||||
options.graphite &&
|
||||
options.graphite.annotationScreenshot
|
||||
? `<a href='${resultPageUrl}' target='_blank'><img src='${screenshotPath}' ${screenshotSize}></a><p><a href='${resultPageUrl}'>Result</a> - <a href='${harPath}'>Download HAR</a></p>`
|
||||
: `<a href='${resultPageUrl}' target='_blank'>Result ${
|
||||
options.browsertime.iterations
|
||||
} run${s}</a>`;
|
||||
if (options.graphite.annotationMessage) {
|
||||
message += options.graphite.annotationMessage;
|
||||
}
|
||||
const message = annotationsHelper.getAnnotationMessage(
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
options
|
||||
);
|
||||
const timestamp = Math.round(time.valueOf() / 1000);
|
||||
const theTags = options.graphite.arrayTags ? tagsArray : tagsString;
|
||||
const postData = `{"what": "${
|
||||
options.browsertime.iterations
|
||||
} run${s}", "tags": ${theTags}, "data": "${message}", "when": ${timestamp}}`;
|
||||
|
|
|
|||
|
|
@ -32,8 +32,10 @@ module.exports = {
|
|||
this.resultUrls = context.resultUrls;
|
||||
this.dataGenerator = new DataGenerator(opts.includeQueryParams, options);
|
||||
this.annotationType = 'webpagetest.pageSummary';
|
||||
this.make = context.messageMaker('influxdb').make;
|
||||
this.sendAnnotation = true;
|
||||
},
|
||||
processMessage(message) {
|
||||
processMessage(message, queue) {
|
||||
const filterRegistry = this.filterRegistry;
|
||||
|
||||
// First catch if we are running Browsertime and/or WebPageTest
|
||||
|
|
@ -44,6 +46,11 @@ module.exports = {
|
|||
this.useScreenshots = message.data.screenshot;
|
||||
this.screenshotType = message.data.screenshotType;
|
||||
}
|
||||
} else if (message.type === 'sitespeedio.setup') {
|
||||
// Let other plugins know that the Graphite plugin is alive
|
||||
queue.postMessage(this.make('graphite.setup'));
|
||||
} else if (message.type === 'grafana.setup') {
|
||||
this.sendAnnotation = false;
|
||||
}
|
||||
|
||||
if (
|
||||
|
|
@ -81,28 +88,21 @@ module.exports = {
|
|||
// when we configured a base url
|
||||
if (
|
||||
message.type === this.annotationType &&
|
||||
this.resultUrls.hasBaseUrl()
|
||||
this.resultUrls.hasBaseUrl() &&
|
||||
this.sendAnnotation
|
||||
) {
|
||||
const resultPageUrl = this.resultUrls.absoluteSummaryPagePath(
|
||||
const absolutePagePath = this.resultUrls.absoluteSummaryPagePath(
|
||||
message.url
|
||||
);
|
||||
let screenshotPath;
|
||||
if (this.useScreenshots) {
|
||||
screenshotPath =
|
||||
resultPageUrl + 'data/screenshots/1.' + this.screenshotType;
|
||||
}
|
||||
const harPath =
|
||||
resultPageUrl +
|
||||
'data/browsertime.har' +
|
||||
(this.options.gzipHAR ? '.gz' : '');
|
||||
|
||||
return sendAnnotations.send(
|
||||
this.options,
|
||||
message.group,
|
||||
message.url,
|
||||
resultPageUrl + 'index.html',
|
||||
screenshotPath,
|
||||
harPath
|
||||
message.group,
|
||||
absolutePagePath,
|
||||
this.useScreenshots,
|
||||
this.screenshotType,
|
||||
this.timestamp,
|
||||
this.options
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,10 +5,19 @@ const log = require('intel').getLogger('sitespeedio.plugin.influxdb');
|
|||
const Promise = require('bluebird');
|
||||
const querystring = require('querystring');
|
||||
const tsdbUtil = require('../../support/tsdbUtil');
|
||||
const annotationsHelper = require('../../support/annotationsHelper');
|
||||
const moment = require('moment');
|
||||
|
||||
module.exports = {
|
||||
send(options, group, url, resultPageUrl, screenshotPath, harPath) {
|
||||
send(
|
||||
url,
|
||||
group,
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
time,
|
||||
options
|
||||
) {
|
||||
// The tags make it possible for the dashboard to use the
|
||||
// templates to choose which annotations that will be showed.
|
||||
// That's why we need to send tags that matches the template
|
||||
|
|
@ -18,15 +27,14 @@ module.exports = {
|
|||
const urlAndGroup = tsdbUtil
|
||||
.getURLAndGroup(options, group, url, options.influxdb.includeQueryParams)
|
||||
.split('.');
|
||||
let tags = `${connectivity},${browser},${urlAndGroup.join(',')}`;
|
||||
let message =
|
||||
screenshotPath &&
|
||||
options.influxdb &&
|
||||
options.influxdb.annotationScreenshot
|
||||
? `<a href='${resultPageUrl}' target='_blank'><img src='${screenshotPath}' width=100%></a><a href='${resultPageUrl}'>Result</a> - <a href='${harPath}'>Download HAR</a>`
|
||||
: `<a href='${resultPageUrl}' target='_blank'>Result ${
|
||||
options.browsertime.iterations
|
||||
} run(s)</a>`;
|
||||
let tags = [connectivity, browser, urlAndGroup[0], urlAndGroup[1]];
|
||||
|
||||
const message = annotationsHelper.getAnnotationMessage(
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
options
|
||||
);
|
||||
const timestamp = Math.round(moment() / 1000);
|
||||
// if we have a category, let us send that category too
|
||||
if (options.influxdb.tags) {
|
||||
|
|
@ -35,7 +43,8 @@ module.exports = {
|
|||
tags += `,${keyAndValue[1]}`;
|
||||
}
|
||||
}
|
||||
const postData = `events title="Sitespeed.io",text="${message}",tags="${tags}" ${timestamp}`;
|
||||
const influxDBTags = annotationsHelper.getTagsAsString(tags);
|
||||
const postData = `events title="Sitespeed.io",text="${message}",tags=${influxDBTags} ${timestamp}`;
|
||||
const postOptions = {
|
||||
hostname: options.influxdb.host,
|
||||
port: options.influxdb.port,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
'use strict';
|
||||
|
||||
module.exports = {
|
||||
getAnnotationMessage(
|
||||
absolutePagePath,
|
||||
screenShotsEnabledInBrowsertime,
|
||||
screenshotType,
|
||||
options
|
||||
) {
|
||||
const screenshotSize = options.mobile ? 'height=200px' : 'width=100%';
|
||||
const resultPageUrl = absolutePagePath + 'index.html';
|
||||
let screenshotPath;
|
||||
if (screenShotsEnabledInBrowsertime) {
|
||||
screenshotPath =
|
||||
absolutePagePath + 'data/screenshots/1.' + screenshotType;
|
||||
}
|
||||
|
||||
const screenshotsEnabledForDatasource =
|
||||
options.graphite.annotationScreenshot ||
|
||||
options.influxdb.annotationScreenshot;
|
||||
const harPath =
|
||||
absolutePagePath +
|
||||
'data/browsertime.har' +
|
||||
(options.gzipHAR ? '.gz' : '');
|
||||
|
||||
const extraMessage = options.graphite.annotationMessage
|
||||
? options.graphite.annotationMessage
|
||||
: options.influxdb.annotationMessage
|
||||
? options.influxdb.annotationMessage
|
||||
: undefined;
|
||||
|
||||
const s = options.browsertime.iterations > 1 ? 's' : '';
|
||||
|
||||
let message =
|
||||
screenShotsEnabledInBrowsertime && screenshotsEnabledForDatasource
|
||||
? `<a href='${resultPageUrl}' target='_blank'><img src='${screenshotPath}' ${screenshotSize}></a><p><a href='${resultPageUrl}'>Result</a> - <a href='${harPath}'>Download HAR</a></p>`
|
||||
: `<a href='${resultPageUrl}' target='_blank'>Result ${
|
||||
options.browsertime.iterations
|
||||
} run${s}</a>`;
|
||||
if (extraMessage) {
|
||||
message += extraMessage;
|
||||
}
|
||||
return message;
|
||||
},
|
||||
getTagsAsString(tags) {
|
||||
return '"' + tags.join(',') + '"';
|
||||
},
|
||||
getTagsAsArray(tags) {
|
||||
const stringTags = [];
|
||||
for (let tag of tags) {
|
||||
stringTags.push('"' + tag + '"');
|
||||
}
|
||||
return '[' + stringTags.join(',') + ']';
|
||||
}
|
||||
};
|
||||
Loading…
Reference in New Issue