sitespeed.io 36.4.0 → 37.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/HELP.md +2 -9
- package/lib/cli/cli.js +28 -97
- package/lib/cli/pluginOptions.js +34 -0
- package/lib/core/logging.js +1 -0
- package/lib/core/pluginLoader.js +12 -6
- package/lib/plugins/browsertime/index.js +4 -2
- package/lib/plugins/budget/junit.js +77 -51
- package/lib/plugins/budget/tap.js +28 -20
- package/lib/plugins/grafana/send-annotation.js +1 -3
- package/lib/plugins/pagexray/index.js +11 -9
- package/lib/plugins/pagexray/pagexrayAggregator.js +2 -1
- package/npm-shrinkwrap.json +20 -1139
- package/package.json +2 -6
- package/lib/plugins/influxdb/data-generator.js +0 -262
- package/lib/plugins/influxdb/index.js +0 -176
- package/lib/plugins/influxdb/send-annotation.js +0 -111
- package/lib/plugins/influxdb/send-annotationV2.js +0 -106
- package/lib/plugins/influxdb/sender.js +0 -26
- package/lib/plugins/influxdb/senderV2.js +0 -38
- package/tools/influxdb/docker-compose.yml +0 -21
package/package.json
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
"sitespeed.io": "./bin/sitespeed.js",
|
|
6
6
|
"sitespeed.io-wpr": "./bin/browsertimeWebPageReplay.js"
|
|
7
7
|
},
|
|
8
|
-
"version": "
|
|
8
|
+
"version": "37.0.0",
|
|
9
9
|
"description": "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.",
|
|
10
10
|
"keywords": [
|
|
11
11
|
"performance",
|
|
@@ -83,20 +83,17 @@
|
|
|
83
83
|
"dependencies": {
|
|
84
84
|
"@aws-sdk/client-s3": "3.717.0",
|
|
85
85
|
"@google-cloud/storage": "7.14.0",
|
|
86
|
-
"@influxdata/influxdb-client": "1.33.2",
|
|
87
86
|
"@sitespeed.io/log": "0.2.6",
|
|
88
87
|
"@sitespeed.io/plugin": "1.0.0",
|
|
89
88
|
"@tgwf/co2": "0.16.4",
|
|
90
89
|
"@slack/webhook": "7.0.4",
|
|
91
90
|
"axe-core": "4.10.2",
|
|
92
|
-
"browsertime": "24.
|
|
91
|
+
"browsertime": "24.3.0",
|
|
93
92
|
"coach-core": "8.1.1",
|
|
94
93
|
"dayjs": "1.11.11",
|
|
95
94
|
"fast-crc32c": "2.0.0",
|
|
96
95
|
"fast-stats": "0.0.7",
|
|
97
96
|
"import-global": "1.1.1",
|
|
98
|
-
"influx": "5.9.3",
|
|
99
|
-
"junit-report-builder": "3.2.1",
|
|
100
97
|
"lodash.get": "4.4.2",
|
|
101
98
|
"lodash.merge": "4.6.2",
|
|
102
99
|
"lodash.set": "4.3.2",
|
|
@@ -105,7 +102,6 @@
|
|
|
105
102
|
"ora": "8.0.1",
|
|
106
103
|
"pug": "3.0.3",
|
|
107
104
|
"simplecrawler": "1.1.9",
|
|
108
|
-
"tape": "5.8.1",
|
|
109
105
|
"yargs": "17.7.2"
|
|
110
106
|
},
|
|
111
107
|
"overrides": {
|
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
import merge from 'lodash.merge';
|
|
2
|
-
|
|
3
|
-
import { flattenMessageData } from '../../support/flattenMessage.js';
|
|
4
|
-
import {
|
|
5
|
-
getConnectivity,
|
|
6
|
-
getURLAndGroup,
|
|
7
|
-
toSafeKey
|
|
8
|
-
} from '../../support/tsdbUtil.js';
|
|
9
|
-
|
|
10
|
-
function getAdditionalTags(key, type) {
|
|
11
|
-
let tags = {};
|
|
12
|
-
const keyArray = key.split('.');
|
|
13
|
-
if (/(^contentTypes)/.test(key)) {
|
|
14
|
-
// contentTypes.favicon.requests.mean
|
|
15
|
-
// contentTypes.favicon.requests
|
|
16
|
-
// contentTypes.css.transferSize
|
|
17
|
-
tags.contentType = keyArray[1];
|
|
18
|
-
} else if (/(^pageTimings|^visualMetrics)/.test(key)) {
|
|
19
|
-
// pageTimings.serverResponseTime.max
|
|
20
|
-
// visualMetrics.SpeedIndex.median
|
|
21
|
-
tags.timings = keyArray[0];
|
|
22
|
-
} else
|
|
23
|
-
switch (type) {
|
|
24
|
-
case 'browsertime.pageSummary': {
|
|
25
|
-
// statistics.timings.pageTimings.backEndTime.median
|
|
26
|
-
// statistics.timings.userTimings.marks.logoTime.median
|
|
27
|
-
// statistics.visualMetrics.SpeedIndex.median
|
|
28
|
-
tags[keyArray[0]] = keyArray[1];
|
|
29
|
-
if (keyArray.length >= 5) {
|
|
30
|
-
tags[keyArray[2]] = keyArray[3];
|
|
31
|
-
}
|
|
32
|
-
if (key.includes('cpu.categories')) {
|
|
33
|
-
tags.cpu = 'category';
|
|
34
|
-
} else if (key.includes('cpu.events')) {
|
|
35
|
-
tags.cpu = 'event';
|
|
36
|
-
} else if (key.includes('cpu.longTasks')) {
|
|
37
|
-
tags.cpu = 'longTask';
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
break;
|
|
41
|
-
}
|
|
42
|
-
case 'browsertime.summary': {
|
|
43
|
-
// firstPaint.median
|
|
44
|
-
// userTimings.marks.logoTime.median
|
|
45
|
-
if (key.includes('userTimings')) {
|
|
46
|
-
tags[keyArray[0]] = keyArray[1];
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
break;
|
|
50
|
-
}
|
|
51
|
-
case 'axe.pageSummary': {
|
|
52
|
-
tags.axeType = keyArray[0];
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
case 'coach.pageSummary': {
|
|
56
|
-
// advice.score
|
|
57
|
-
// advice.performance.score
|
|
58
|
-
if (keyArray.length > 2) {
|
|
59
|
-
tags.advice = keyArray[1];
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// set the actual advice name
|
|
63
|
-
// advice.performance.adviceList.cacheHeaders.score
|
|
64
|
-
if (keyArray.length > 4) {
|
|
65
|
-
tags.adviceName = keyArray[3];
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
break;
|
|
69
|
-
}
|
|
70
|
-
case 'coach.summary': {
|
|
71
|
-
// score.max
|
|
72
|
-
// performance.score.median
|
|
73
|
-
if (keyArray.length === 3) {
|
|
74
|
-
tags.advice = keyArray[0];
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
case 'pagexray.summary': {
|
|
80
|
-
// firstParty.requests.min pagexray.summary
|
|
81
|
-
// requests.median
|
|
82
|
-
// responseCodes.307.max pagexray.summary
|
|
83
|
-
// requests.min pagexray.summary
|
|
84
|
-
if (key.includes('responseCodes')) {
|
|
85
|
-
tags.responseCodes = 'response';
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (key.includes('firstParty') || key.includes('thirdParty')) {
|
|
89
|
-
tags.party = keyArray[0];
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
case 'pagexray.pageSummary': {
|
|
95
|
-
// thirdParty.contentTypes.json.requests pagexray.pageSummary
|
|
96
|
-
// thirdParty.requests pagexray.pageSummary
|
|
97
|
-
// firstParty.cookieStats.max pagexray.pageSummary
|
|
98
|
-
// responseCodes.200 pagexray.pageSummary
|
|
99
|
-
// expireStats.max pagexray.pageSummary
|
|
100
|
-
// totalDomains pagexray.pageSummary
|
|
101
|
-
if (key.includes('firstParty') || key.includes('thirdParty')) {
|
|
102
|
-
tags.party = keyArray[0];
|
|
103
|
-
}
|
|
104
|
-
if (key.includes('responseCodes')) {
|
|
105
|
-
tags.responseCodes = 'response';
|
|
106
|
-
}
|
|
107
|
-
if (key.includes('contentTypes')) {
|
|
108
|
-
tags.contentType = keyArray[2];
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
case 'thirdparty.pageSummary': {
|
|
114
|
-
tags.thirdPartyCategory = keyArray[1];
|
|
115
|
-
tags.thirdPartyType = keyArray[2];
|
|
116
|
-
|
|
117
|
-
break;
|
|
118
|
-
}
|
|
119
|
-
case 'lighthouse.pageSummary': {
|
|
120
|
-
// categories.seo.score
|
|
121
|
-
// categories.performance.score
|
|
122
|
-
if (key.includes('score')) {
|
|
123
|
-
tags.audit = keyArray[1];
|
|
124
|
-
}
|
|
125
|
-
if (key.includes('audits')) {
|
|
126
|
-
tags.audit = keyArray[1];
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
case 'crux.pageSummary': {
|
|
132
|
-
tags.experience = keyArray[0];
|
|
133
|
-
tags.formFactor = keyArray[1];
|
|
134
|
-
tags.metric = keyArray[2];
|
|
135
|
-
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
case 'gpsi.pageSummary': {
|
|
139
|
-
if (key.includes('googleWebVitals')) {
|
|
140
|
-
tags.testType = 'googleWebVitals';
|
|
141
|
-
} else if (key.includes('score')) {
|
|
142
|
-
tags.testType = 'score';
|
|
143
|
-
} else if (key.includes('loadingExperience')) {
|
|
144
|
-
tags.experience = keyArray[0];
|
|
145
|
-
tags.metric = keyArray[1];
|
|
146
|
-
tags.testType = 'crux';
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
break;
|
|
150
|
-
}
|
|
151
|
-
default:
|
|
152
|
-
// console.log('Missed added tags to ' + key + ' ' + type);
|
|
153
|
-
}
|
|
154
|
-
return tags;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
function getFieldAndSeriesName(key) {
|
|
158
|
-
const functions = [
|
|
159
|
-
'min',
|
|
160
|
-
'p10',
|
|
161
|
-
'median',
|
|
162
|
-
'mean',
|
|
163
|
-
'avg',
|
|
164
|
-
'max',
|
|
165
|
-
'p90',
|
|
166
|
-
'p99',
|
|
167
|
-
'mdev',
|
|
168
|
-
'stddev',
|
|
169
|
-
'rsd'
|
|
170
|
-
];
|
|
171
|
-
const keyArray = key.split('.');
|
|
172
|
-
const end = keyArray.pop();
|
|
173
|
-
if (functions.includes(end)) {
|
|
174
|
-
return { field: end, seriesName: keyArray.pop() };
|
|
175
|
-
}
|
|
176
|
-
return { field: 'value', seriesName: end };
|
|
177
|
-
}
|
|
178
|
-
export class InfluxDBDataGenerator {
|
|
179
|
-
constructor(includeQueryParameters, options) {
|
|
180
|
-
this.includeQueryParams = !!includeQueryParameters;
|
|
181
|
-
this.options = options;
|
|
182
|
-
this.defaultTags = {};
|
|
183
|
-
for (let row of options.influxdb.tags.split(',')) {
|
|
184
|
-
const keyAndValue = row.split('=');
|
|
185
|
-
this.defaultTags[keyAndValue[0]] = keyAndValue[1];
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
dataFromMessage(message, time, alias) {
|
|
190
|
-
function getTagsFromMessage(
|
|
191
|
-
message,
|
|
192
|
-
includeQueryParameters,
|
|
193
|
-
options,
|
|
194
|
-
defaultTags
|
|
195
|
-
) {
|
|
196
|
-
const tags = merge({}, defaultTags);
|
|
197
|
-
let typeParts = message.type.split('.');
|
|
198
|
-
tags.origin = typeParts[0];
|
|
199
|
-
typeParts.push(typeParts.shift());
|
|
200
|
-
tags.summaryType = typeParts[0];
|
|
201
|
-
|
|
202
|
-
// always have browser and connectivity in Browsertime and related tools
|
|
203
|
-
if (
|
|
204
|
-
/(^pagexray|^coach|^browsertime|^thirdparty|^axe|^sustainable)/.test(
|
|
205
|
-
message.type
|
|
206
|
-
)
|
|
207
|
-
) {
|
|
208
|
-
// if we have a friendly name for your connectivity, use that!
|
|
209
|
-
let connectivity = getConnectivity(options);
|
|
210
|
-
tags.connectivity = connectivity;
|
|
211
|
-
tags.browser = options.browser;
|
|
212
|
-
} else if (/(^gpsi)/.test(message.type)) {
|
|
213
|
-
tags.strategy = options.mobile ? 'mobile' : 'desktop';
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
// if we get a URL type, add the URL
|
|
217
|
-
if (message.url) {
|
|
218
|
-
const urlAndGroup = getURLAndGroup(
|
|
219
|
-
options,
|
|
220
|
-
message.group,
|
|
221
|
-
message.url,
|
|
222
|
-
includeQueryParameters,
|
|
223
|
-
alias
|
|
224
|
-
).split('.');
|
|
225
|
-
tags.page = urlAndGroup[1];
|
|
226
|
-
tags.group = urlAndGroup[0];
|
|
227
|
-
} else if (message.group) {
|
|
228
|
-
// add the group of the summary message
|
|
229
|
-
tags.group = toSafeKey(message.group, options.influxdb.groupSeparator);
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (options.slug) {
|
|
233
|
-
tags.testName = options.slug;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
return tags;
|
|
237
|
-
}
|
|
238
|
-
return Object.entries(flattenMessageData(message)).reduce(
|
|
239
|
-
(entries, [key, value]) => {
|
|
240
|
-
const fieldAndSeriesName = getFieldAndSeriesName(key);
|
|
241
|
-
let tags = getTagsFromMessage(
|
|
242
|
-
message,
|
|
243
|
-
this.includeQueryParams,
|
|
244
|
-
this.options,
|
|
245
|
-
this.defaultTags
|
|
246
|
-
);
|
|
247
|
-
tags = { ...getAdditionalTags(key, message.type), ...tags };
|
|
248
|
-
const point = {
|
|
249
|
-
time: time.valueOf(),
|
|
250
|
-
[fieldAndSeriesName.field]: value
|
|
251
|
-
};
|
|
252
|
-
entries.push({
|
|
253
|
-
tags,
|
|
254
|
-
seriesName: fieldAndSeriesName.seriesName,
|
|
255
|
-
point
|
|
256
|
-
});
|
|
257
|
-
return entries;
|
|
258
|
-
},
|
|
259
|
-
[]
|
|
260
|
-
);
|
|
261
|
-
}
|
|
262
|
-
}
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
import { getLogger } from '@sitespeed.io/log';
|
|
2
|
-
import dayjs from 'dayjs';
|
|
3
|
-
|
|
4
|
-
import { SitespeedioPlugin } from '@sitespeed.io/plugin';
|
|
5
|
-
import { InfluxDBSender as Sender } from './sender.js';
|
|
6
|
-
import { InfluxDB2Sender as SenderV2 } from './senderV2.js';
|
|
7
|
-
import { sendV1 } from './send-annotation.js';
|
|
8
|
-
import { sendV2 } from './send-annotationV2.js';
|
|
9
|
-
import { InfluxDBDataGenerator as DataGenerator } from './data-generator.js';
|
|
10
|
-
import { throwIfMissing, isEmpty } from '../../support/util.js';
|
|
11
|
-
|
|
12
|
-
const log = getLogger('sitespeedio.plugin.influxdb');
|
|
13
|
-
export default class InfluxDBPlugin extends SitespeedioPlugin {
|
|
14
|
-
constructor(options, context, queue) {
|
|
15
|
-
super({ name: 'influxdb', options, context, queue });
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
open(context, options) {
|
|
19
|
-
throwIfMissing(options.influxdb, ['host', 'database'], 'influxdb');
|
|
20
|
-
this.filterRegistry = context.filterRegistry;
|
|
21
|
-
log.debug(
|
|
22
|
-
'Setup InfluxDB host %s and database %s',
|
|
23
|
-
options.influxdb.host,
|
|
24
|
-
options.influxdb.database
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const options_ = options.influxdb;
|
|
28
|
-
this.options = options;
|
|
29
|
-
this.sender =
|
|
30
|
-
options_.version == 1 ? new Sender(options_) : new SenderV2(options_);
|
|
31
|
-
this.timestamp = context.timestamp;
|
|
32
|
-
this.resultUrls = context.resultUrls;
|
|
33
|
-
this.dataGenerator = new DataGenerator(
|
|
34
|
-
options_.includeQueryParams,
|
|
35
|
-
options
|
|
36
|
-
);
|
|
37
|
-
this.messageTypesToFireAnnotations = [];
|
|
38
|
-
this.receivedTypesThatFireAnnotations = {};
|
|
39
|
-
this.make = context.messageMaker('influxdb').make;
|
|
40
|
-
this.sendAnnotation = true;
|
|
41
|
-
this.alias = {};
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
processMessage(message, queue) {
|
|
45
|
-
const filterRegistry = this.filterRegistry;
|
|
46
|
-
|
|
47
|
-
// First catch if we are running Browsertime and/or WebPageTest
|
|
48
|
-
switch (message.type) {
|
|
49
|
-
case 'browsertime.setup': {
|
|
50
|
-
this.messageTypesToFireAnnotations.push('browsertime.pageSummary');
|
|
51
|
-
this.usingBrowsertime = true;
|
|
52
|
-
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
case 'browsertime.config': {
|
|
56
|
-
if (message.data.screenshot) {
|
|
57
|
-
this.useScreenshots = message.data.screenshot;
|
|
58
|
-
this.screenshotType = message.data.screenshotType;
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
case 'sitespeedio.setup': {
|
|
64
|
-
// Let other plugins know that the InfluxDB plugin is alive
|
|
65
|
-
queue.postMessage(this.make('influxdb.setup'));
|
|
66
|
-
|
|
67
|
-
break;
|
|
68
|
-
}
|
|
69
|
-
case 'grafana.setup': {
|
|
70
|
-
this.sendAnnotation = false;
|
|
71
|
-
|
|
72
|
-
break;
|
|
73
|
-
}
|
|
74
|
-
// No default
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
if (message.type === 'browsertime.alias') {
|
|
78
|
-
this.alias[message.url] = message.data;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (
|
|
82
|
-
!(
|
|
83
|
-
message.type.endsWith('.summary') ||
|
|
84
|
-
message.type.endsWith('.pageSummary')
|
|
85
|
-
)
|
|
86
|
-
) {
|
|
87
|
-
return;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (this.messageTypesToFireAnnotations.includes(message.type)) {
|
|
91
|
-
this.receivedTypesThatFireAnnotations[message.url]
|
|
92
|
-
? this.receivedTypesThatFireAnnotations[message.url]++
|
|
93
|
-
: (this.receivedTypesThatFireAnnotations[message.url] = 1);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Let us skip this for a while and concentrate on the real deal
|
|
97
|
-
if (
|
|
98
|
-
/(^largestassets|^slowestassets|^aggregateassets|^domains)/.test(
|
|
99
|
-
message.type
|
|
100
|
-
)
|
|
101
|
-
)
|
|
102
|
-
return;
|
|
103
|
-
|
|
104
|
-
// we only sends individual groups to Influx, not the
|
|
105
|
-
// total of all groups (you can calculate that yourself)
|
|
106
|
-
if (message.group === 'total') {
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
message = filterRegistry.filterMessage(message);
|
|
111
|
-
if (isEmpty(message.data)) return;
|
|
112
|
-
|
|
113
|
-
let data = this.dataGenerator.dataFromMessage(
|
|
114
|
-
message,
|
|
115
|
-
message.type === 'browsertime.pageSummary'
|
|
116
|
-
? dayjs(message.runTime)
|
|
117
|
-
: this.timestamp,
|
|
118
|
-
this.alias
|
|
119
|
-
);
|
|
120
|
-
|
|
121
|
-
if (data.length > 0) {
|
|
122
|
-
log.debug('Send the following data to InfluxDB: %:2j', data);
|
|
123
|
-
return this.sender.send(data).then(() => {
|
|
124
|
-
// Make sure we only send the annotation once per URL:
|
|
125
|
-
// If we run browsertime, always send on browsertime.pageSummary
|
|
126
|
-
// If we run WebPageTest standalone, send on webPageTestSummary
|
|
127
|
-
// when we configured a base url
|
|
128
|
-
if (
|
|
129
|
-
this.receivedTypesThatFireAnnotations[message.url] ===
|
|
130
|
-
this.messageTypesToFireAnnotations.length &&
|
|
131
|
-
this.resultUrls.hasBaseUrl() &&
|
|
132
|
-
this.sendAnnotation
|
|
133
|
-
) {
|
|
134
|
-
const absolutePagePath = this.resultUrls.absoluteSummaryPagePath(
|
|
135
|
-
message.url,
|
|
136
|
-
this.alias[message.url]
|
|
137
|
-
);
|
|
138
|
-
this.receivedTypesThatFireAnnotations[message.url] = 0;
|
|
139
|
-
|
|
140
|
-
return this.options.influxdb.version == 2
|
|
141
|
-
? sendV2(
|
|
142
|
-
message.url,
|
|
143
|
-
message.group,
|
|
144
|
-
absolutePagePath,
|
|
145
|
-
this.useScreenshots,
|
|
146
|
-
this.screenshotType,
|
|
147
|
-
// Browsertime pass on when the first run was done for that URL
|
|
148
|
-
message.runTime,
|
|
149
|
-
this.alias,
|
|
150
|
-
this.usingBrowsertime,
|
|
151
|
-
this.options
|
|
152
|
-
)
|
|
153
|
-
: sendV1(
|
|
154
|
-
message.url,
|
|
155
|
-
message.group,
|
|
156
|
-
absolutePagePath,
|
|
157
|
-
this.useScreenshots,
|
|
158
|
-
this.screenshotType,
|
|
159
|
-
// Browsertime pass on when the first run was done for that URL
|
|
160
|
-
message.runTime,
|
|
161
|
-
this.alias,
|
|
162
|
-
this.usingBrowsertime,
|
|
163
|
-
this.options
|
|
164
|
-
);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
} else {
|
|
168
|
-
return Promise.reject(
|
|
169
|
-
new Error(
|
|
170
|
-
'No data to send to influxdb for message:\n' +
|
|
171
|
-
JSON.stringify(message, undefined, 2)
|
|
172
|
-
)
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
}
|
|
@@ -1,111 +0,0 @@
|
|
|
1
|
-
import http from 'node:http';
|
|
2
|
-
import https from 'node:https';
|
|
3
|
-
import { stringify } from 'node:querystring';
|
|
4
|
-
|
|
5
|
-
import { getLogger } from '@sitespeed.io/log';
|
|
6
|
-
import dayjs from 'dayjs';
|
|
7
|
-
|
|
8
|
-
import { getConnectivity, getURLAndGroup } from '../../support/tsdbUtil.js';
|
|
9
|
-
import {
|
|
10
|
-
getAnnotationMessage,
|
|
11
|
-
getTagsAsString
|
|
12
|
-
} from '../../support/annotationsHelper.js';
|
|
13
|
-
|
|
14
|
-
const log = getLogger('sitespeedio.plugin.influxdb');
|
|
15
|
-
|
|
16
|
-
export function sendV1(
|
|
17
|
-
url,
|
|
18
|
-
group,
|
|
19
|
-
absolutePagePath,
|
|
20
|
-
screenShotsEnabledInBrowsertime,
|
|
21
|
-
screenshotType,
|
|
22
|
-
runTime,
|
|
23
|
-
alias,
|
|
24
|
-
usingBrowsertime,
|
|
25
|
-
options
|
|
26
|
-
) {
|
|
27
|
-
// The tags make it possible for the dashboard to use the
|
|
28
|
-
// templates to choose which annotations that will be showed.
|
|
29
|
-
// That's why we need to send tags that matches the template
|
|
30
|
-
// variables in Grafana.
|
|
31
|
-
const connectivity = getConnectivity(options);
|
|
32
|
-
const browser = options.browser;
|
|
33
|
-
const urlAndGroup = getURLAndGroup(
|
|
34
|
-
options,
|
|
35
|
-
group,
|
|
36
|
-
url,
|
|
37
|
-
options.influxdb.includeQueryParams,
|
|
38
|
-
alias
|
|
39
|
-
).split('.');
|
|
40
|
-
let tags = [connectivity, browser, urlAndGroup[0], urlAndGroup[1]];
|
|
41
|
-
|
|
42
|
-
if (options.slug) {
|
|
43
|
-
tags.push(options.slug);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
const message = getAnnotationMessage(
|
|
47
|
-
absolutePagePath,
|
|
48
|
-
screenShotsEnabledInBrowsertime,
|
|
49
|
-
screenshotType,
|
|
50
|
-
undefined,
|
|
51
|
-
usingBrowsertime,
|
|
52
|
-
options
|
|
53
|
-
);
|
|
54
|
-
const timestamp = runTime
|
|
55
|
-
? Math.round(dayjs(runTime) / 1000)
|
|
56
|
-
: Math.round(dayjs() / 1000);
|
|
57
|
-
// if we have a category, let us send that category too
|
|
58
|
-
if (options.influxdb.tags) {
|
|
59
|
-
for (let row of options.influxdb.tags.split(',')) {
|
|
60
|
-
const keyAndValue = row.split('=');
|
|
61
|
-
tags.push(keyAndValue[1]);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
const influxDBTags = getTagsAsString(tags);
|
|
65
|
-
const postData = `events title="Sitespeed.io",text="${message}",tags=${influxDBTags} ${timestamp}`;
|
|
66
|
-
const postOptions = {
|
|
67
|
-
hostname: options.influxdb.host,
|
|
68
|
-
port: options.influxdb.port,
|
|
69
|
-
path: '/write?db=' + options.influxdb.database + '&precision=s',
|
|
70
|
-
method: 'POST',
|
|
71
|
-
headers: {
|
|
72
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
73
|
-
'Content-Length': Buffer.byteLength(postData)
|
|
74
|
-
}
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
if (options.influxdb.username) {
|
|
78
|
-
postOptions.path =
|
|
79
|
-
postOptions.path +
|
|
80
|
-
'&' +
|
|
81
|
-
stringify({
|
|
82
|
-
u: options.influxdb.username,
|
|
83
|
-
p: options.influxdb.password
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return new Promise((resolve, reject) => {
|
|
88
|
-
log.debug('Send annotation to Influx: %j', postData);
|
|
89
|
-
// not perfect but maybe work for us
|
|
90
|
-
const library = options.influxdb.protocol === 'https' ? https : http;
|
|
91
|
-
const request = library.request(postOptions, res => {
|
|
92
|
-
if (res.statusCode === 204) {
|
|
93
|
-
res.setEncoding('utf8');
|
|
94
|
-
log.debug('Sent annotation to InfluxDB');
|
|
95
|
-
resolve();
|
|
96
|
-
} else {
|
|
97
|
-
const e = new Error(
|
|
98
|
-
`Got ${res.statusCode} from InfluxDB when sending annotation ${res.statusMessage}`
|
|
99
|
-
);
|
|
100
|
-
log.warn(e.message);
|
|
101
|
-
reject(e);
|
|
102
|
-
}
|
|
103
|
-
});
|
|
104
|
-
request.on('error', error => {
|
|
105
|
-
log.error('Got error from InfluxDB when sending annotation', error);
|
|
106
|
-
reject(error);
|
|
107
|
-
});
|
|
108
|
-
request.write(postData);
|
|
109
|
-
request.end();
|
|
110
|
-
});
|
|
111
|
-
}
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
import http from 'node:http';
|
|
2
|
-
import https from 'node:https';
|
|
3
|
-
|
|
4
|
-
import { getLogger } from '@sitespeed.io/log';
|
|
5
|
-
import dayjs from 'dayjs';
|
|
6
|
-
|
|
7
|
-
import { getConnectivity, getURLAndGroup } from '../../support/tsdbUtil.js';
|
|
8
|
-
import {
|
|
9
|
-
getAnnotationMessage,
|
|
10
|
-
getTagsAsString
|
|
11
|
-
} from '../../support/annotationsHelper.js';
|
|
12
|
-
|
|
13
|
-
const log = getLogger('sitespeedio.plugin.influxdb');
|
|
14
|
-
|
|
15
|
-
export function sendV2(
|
|
16
|
-
url,
|
|
17
|
-
group,
|
|
18
|
-
absolutePagePath,
|
|
19
|
-
screenShotsEnabledInBrowsertime,
|
|
20
|
-
screenshotType,
|
|
21
|
-
runTime,
|
|
22
|
-
alias,
|
|
23
|
-
usingBrowsertime,
|
|
24
|
-
options
|
|
25
|
-
) {
|
|
26
|
-
// The tags make it possible for the dashboard to use the
|
|
27
|
-
// templates to choose which annotations that will be showed.
|
|
28
|
-
// That's why we need to send tags that matches the template
|
|
29
|
-
// variables in Grafana.
|
|
30
|
-
const connectivity = getConnectivity(options);
|
|
31
|
-
const browser = options.browser;
|
|
32
|
-
const urlAndGroup = getURLAndGroup(
|
|
33
|
-
options,
|
|
34
|
-
group,
|
|
35
|
-
url,
|
|
36
|
-
options.influxdb.includeQueryParams,
|
|
37
|
-
alias
|
|
38
|
-
).split('.');
|
|
39
|
-
let tags = [
|
|
40
|
-
`connectivity=${connectivity}`,
|
|
41
|
-
`browser=${browser}`,
|
|
42
|
-
`group=${urlAndGroup[0]}`,
|
|
43
|
-
`page=${urlAndGroup[1]}`
|
|
44
|
-
];
|
|
45
|
-
|
|
46
|
-
if (options.slug) {
|
|
47
|
-
tags.push(`slug=${options.slug}`);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const message = getAnnotationMessage(
|
|
51
|
-
absolutePagePath,
|
|
52
|
-
screenShotsEnabledInBrowsertime,
|
|
53
|
-
screenshotType,
|
|
54
|
-
undefined,
|
|
55
|
-
usingBrowsertime,
|
|
56
|
-
options
|
|
57
|
-
);
|
|
58
|
-
const timestamp = runTime
|
|
59
|
-
? Math.round(dayjs(runTime) / 1000)
|
|
60
|
-
: Math.round(dayjs() / 1000);
|
|
61
|
-
// if we have a category, let us send that category too
|
|
62
|
-
if (options.influxdb.tags) {
|
|
63
|
-
for (const tag of options.influxdb.tags.split(',')) {
|
|
64
|
-
tags.push(tag);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
const influxDBTags = tags.join(',');
|
|
68
|
-
const grafanaTags = getTagsAsString(tags.map(pair => pair.split('=')[1]));
|
|
69
|
-
const postData = `annotations,${influxDBTags} title="Sitespeed.io",text="${message}",tags=${grafanaTags} ${timestamp}`;
|
|
70
|
-
const postOptions = {
|
|
71
|
-
hostname: options.influxdb.host,
|
|
72
|
-
port: options.influxdb.port,
|
|
73
|
-
path: `/api/v2/write?org=${options.influxdb.organisation}&bucket=${options.influxdb.database}&precision=s`,
|
|
74
|
-
method: 'POST',
|
|
75
|
-
headers: {
|
|
76
|
-
'Content-Type': 'application/x-www-form-urlencoded',
|
|
77
|
-
'Content-Length': Buffer.byteLength(postData),
|
|
78
|
-
Authorization: `Token ${options.influxdb.token}`
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
return new Promise((resolve, reject) => {
|
|
83
|
-
log.debug('Send annotation to Influx: %j', postData);
|
|
84
|
-
// not perfect but maybe work for us
|
|
85
|
-
const library = options.influxdb.protocol === 'https' ? https : http;
|
|
86
|
-
const request = library.request(postOptions, res => {
|
|
87
|
-
if (res.statusCode === 204) {
|
|
88
|
-
res.setEncoding('utf8');
|
|
89
|
-
log.debug('Sent annotation to InfluxDB');
|
|
90
|
-
resolve();
|
|
91
|
-
} else {
|
|
92
|
-
const e = new Error(
|
|
93
|
-
`Got ${res.statusCode} from InfluxDB when sending annotation ${res.statusMessage}`
|
|
94
|
-
);
|
|
95
|
-
log.warn(e.message);
|
|
96
|
-
reject(e);
|
|
97
|
-
}
|
|
98
|
-
});
|
|
99
|
-
request.on('error', error => {
|
|
100
|
-
log.error('Got error from InfluxDB when sending annotation', error);
|
|
101
|
-
reject(error);
|
|
102
|
-
});
|
|
103
|
-
request.write(postData);
|
|
104
|
-
request.end();
|
|
105
|
-
});
|
|
106
|
-
}
|