UNPKG

sitespeed.io

Version:

sitespeed.io is an open-source tool for comprehensive web performance analysis, enabling you to test, monitor, and optimize your website’s speed using real browsers in various environments.

134 lines (126 loc) 3.98 kB
import http from 'node:http'; import https from 'node:https'; import { createRequire } from 'node:module'; import { getLogger } from '@sitespeed.io/log'; import { getConnectivity, getURLAndGroup } from '../../support/tsdbUtil.js'; import { getTagsAsArray, getAnnotationMessage } from '../../support/annotationsHelper.js'; import { toArray } from '../../support/util.js'; const require = createRequire(import.meta.url); const version = require('../../../package.json').version; const log = getLogger('sitespeedio.plugin.grafana'); export function send( url, group, absolutePagePath, screenShotsEnabledInBrowsertime, screenshotType, time, tsdbType, alias, webPageTestExtraData, usingBrowsertime, browserNameAndVersion, 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 = getConnectivity(options); const browser = options.browser; // Hmm, here we have hardcoded Graphite ... const namespace = options.graphite.namespace.split('.'); const urlAndGroup = getURLAndGroup( options, group, url, options.graphite.includeQueryParams, alias ).split('.'); const tags = [ connectivity, browser, namespace[0], namespace[1], urlAndGroup[0], urlAndGroup[1] ]; // Avoid having the same annotations twice https://github.com/sitespeedio/sitespeed.io/issues/3277# if (options.slug) { tags.push(options.slug); } const extraTags = 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 = getTagsAsArray(tags); const message = getAnnotationMessage( absolutePagePath, screenShotsEnabledInBrowsertime, screenshotType, undefined, usingBrowsertime, options ); let what = version + (browserNameAndVersion ? ` - ${browserNameAndVersion.version}` : ''); if (options.grafana.annotationTitle) { what = options.grafana.annotationTitle; } const timestamp = Math.round(time.valueOf() / 1000); const postData = `{"what": "${what}", "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) { log.debug('Using auth for Grafana'); postOptions.headers.Authorization = options.grafana.auth.startsWith('Bearer') || options.grafana.auth.startsWith('Basic') ? options.grafana.auth : '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 library = options.grafana.port === 443 ? https : http; const request = library.request(postOptions, res => { if (res.statusCode === 200) { res.setEncoding('utf8'); log.debug('Sent annotation to Grafana'); resolve(); } else { const e = new Error( `Got ${res.statusCode} from Grafana when sending annotation` ); if (res.statusCode === 403) { log.warn('Authentication required.', e.message); } else if (res.statusCode === 401) { log.warn('No valid authentication.', e.message); } else { log.warn(e.message); } reject(e); } }); request.on('error', error => { log.error('Got error from Grafana when sending annotation', error); reject(error); }); request.write(postData); request.end(); }); }