Skip to content
This repository was archived by the owner on Apr 5, 2022. It is now read-only.

Commit 28215d1

Browse files
author
Winni Neessen
authored
Merge pull request #5 from wneessen/dev
v1.3.2
2 parents 9b0730d + e62141a commit 28215d1

22 files changed

+1208
-80
lines changed

.gitignore

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ lerna-debug.log*
88
.vscode/*
99
log/*
1010
!log/.gitkeep
11-
conf/*
12-
!conf/websitebench.conf
11+
config/*
12+
!config/websitebench.conf
1313

1414

1515
# Diagnostic reports (https://nodejs.org/api/report.html)

Dockerfile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ RUN /usr/bin/groupadd -r websitebench && /usr/bin/useradd -r -g websiteb
88
COPY ["LICENSE", "README.md", "package.json", "package-lock.json", "/opt/websiteBench/"]
99
COPY ["dist", "/opt/websiteBench/dist"]
1010
COPY ["log", "/opt/websiteBench/log"]
11-
COPY ["conf", "/opt/websiteBench/conf"]
11+
COPY ["config", "/opt/websiteBench/config"]
1212
RUN chown -R websitebench:websitebench /opt/websiteBench
1313
WORKDIR /opt/websiteBench
1414
USER websitebench
1515
RUN npm install
16-
VOLUME ["/opt/websiteBench/conf", "/opt/websiteBench/log"]
16+
VOLUME ["/opt/websiteBench/config", "/opt/websiteBench/log"]
1717
ENTRYPOINT ["/usr/bin/node", "dist/websiteBench.js"]

README.md

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ websiteBench will measure website performance and propagate the results into an
33

44
## Requirements
55
This service requires some NodeJS and some modules to work:
6-
- [NodeJS](https://nodejs.org/en/)
7-
- [Google Puppeteer](https://pptr.dev/)
86
- [Arg](https://www.npmjs.com/package/arg)
97
- [Node-Influx](https://node-influx.github.io/)
8+
- [NodeJS](https://nodejs.org/en/)
9+
- [node-libcurl](https://github.com/JCMais/node-libcurl/)
10+
- [Google Puppeteer](https://pptr.dev/)
11+
- [Q](https://github.com/kriskowal/q)
1012
- [tslog](https://tslog.js.org/)
1113

1214
The modules should be automagically be installed by running: ```npm install```
@@ -51,7 +53,7 @@ To run the Docker image simply issue the following command:
5153
```
5254
- Run the docker image
5355
```sh
54-
$ docker run --security-opt seccomp=wb-seccomp.json -v /var/db/websiteBench/config/:/opt/websiteBench/conf/ -v /var/db/websiteBench/log/:/opt/websiteBench/log/ website-bench:prod -c conf/yourconfig.conf
56+
$ docker run --security-opt seccomp=wb-seccomp.json -v /var/db/websiteBench/config/:/opt/websiteBench/config/ -v /var/db/websiteBench/log/:/opt/websiteBench/log/ website-bench:prod -c config/yourconfig.conf
5557
```
5658
(You can add additional CLI parameters if needed)
5759

@@ -63,7 +65,8 @@ The config accepts the following options:
6365
{
6466
"siteName": "Your Site No. 1",
6567
"siteUrl": "https://example.com/fooo.html",
66-
"checkInterval": 130
68+
"checkInterval": 130,
69+
"checkType": "curl"
6770
},
6871
{
6972
"siteName": "Your other great Site",
@@ -79,14 +82,19 @@ The config accepts the following options:
7982
"database": "websitebench",
8083
"ignoressl": false
8184
},
82-
"allowCaching": false
85+
"allowCaching": false,
86+
"logLevel": "info",
87+
"maxConcurrentJobs": 5,
88+
"instanceName": "DC1-CGN-I1"
8389
}
8490
```
8591
- ```websiteList (Array<IWebEntry>)```: List of websites to collect performance data on
8692
- ```influxDb (IInfluxDbConfig)```: InfluxDB config settings
8793
- ```allowCaching (Boolean)```: If set, the browser will not open Incognito instances, but simple new pages
8894
- ```userAgent (String)```: Override the browser User-Agent
95+
- ```instanceName (String)```: Name of the instance running the checks (will be tagged in InfluxDB accordingly)
8996
- ```logResErrors (Boolean)```: If set, resource errors of the web requests will be logged (same as ```--log-resource-errors```)
97+
- ```ignoreSslErrors (Boolean)```: If set, Chrome/cURL will not error on invalid SSL certificates
9098
- ```maxConcurrentJobs (Number)```: Number of concurrently executed performance checks
9199
- ```logLevel (ILogLevel)```: Define the loglevel
92100

@@ -95,6 +103,7 @@ The config accepts the following options:
95103
- ```siteName (String)```: The name of the site you are monitoring (will be the tag in the InfluxDB)
96104
- ```siteUrl (String)```: The URL to monitor
97105
- ```checkInterval (Number)```: The interval to perform the checks on (in seconds). Minimum value is 60 seconds.
106+
- ```checkType (String)```: The type of performance check to run. Can be either "curl" or "browser" (Default: browser)
98107
- ```IInfluxDbConfig (Object)```: Consists of the following settings:
99108
- ```hostname (String)```: Hostname or IP of the InfluxDB server
100109
- ```database (String)```: InfluxDB database name to store the metrics in
@@ -109,11 +118,11 @@ The server provides the following CLI parameters to override defaults
109118

110119
- ```-c, --config <filepath> ```: Path to config file
111120
- ```-s, --secrets <filepath> ```: Path to secrets config file
112-
- ```--ignore-ssl-errors```: Ignore HTTPS errors
113-
- ```--log-resource-errors```: If set, resource errors of the web requests will be logged
114121
- ```-d, --debug```: Enable DEBUG mode (more logging)
115122
- ```--no-headless```: If set, the browser will start in non-headless mode
116123
- ```--no-sandbox```: If set, the browser is started in no-sandbox mode (**DANGEROUS**: Only use if you are sure what you are doing)
124+
- ```--ignore-ssl-errors```: Ignore HTTPS errors
125+
- ```--log-resource-errors```: If set, resource errors of the web requests will be logged
117126
- ```--browserpath <path to browser executabel>```: Run Puppeteer with a different browser (Chrome/Firefox supported)
118127
- ```--browsertype <chrome|firefox>```: Run Puppeteer with a different browser type (Requires: --browserpath to be set)
119128

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@
33
{
44
"siteName": "Your Site No. 1",
55
"siteUrl": "https://example.com/fooo.html",
6-
"checkInterval": 130
6+
"checkInterval": 130,
7+
"checkType": "curl"
78
},
89
{
910
"siteName": "Your other great Site",
@@ -18,5 +19,9 @@
1819
"port": 443,
1920
"database": "websitebench",
2021
"ignoressl": false
21-
}
22+
},
23+
"allowCaching": false
24+
"logLevel": "info",
25+
"maxConcurrentJobs": 5,
26+
"instanceName": "DC1-CGN-I1"
2227
}

dist/lib/websiteBenchBrowser.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export default class WebsiteBenchBrowser {
99
private logObj;
1010
private numOfRetries;
1111
constructor(browserObj: Puppeteer.Browser, configObj: IWebsiteBenchConfig, logObj: Logger);
12-
processPage(websiteEntry: IWebsiteEntry): Promise<IPerformanceData>;
12+
processPageWithBrowser(websiteEntry: IWebsiteEntry): Promise<IPerformanceData>;
13+
processPageWithCurl(websiteEntry: IWebsiteEntry): Promise<IPerformanceData>;
1314
private eventTriggered;
1415
private errorTriggered;
1516
private processPerformanceData;

dist/lib/websiteBenchBrowser.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/lib/websiteBenchBrowser.js

Lines changed: 101 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,30 @@
11
"use strict";
2+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3+
if (k2 === undefined) k2 = k;
4+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5+
}) : (function(o, m, k, k2) {
6+
if (k2 === undefined) k2 = k;
7+
o[k2] = m[k];
8+
}));
9+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10+
Object.defineProperty(o, "default", { enumerable: true, value: v });
11+
}) : function(o, v) {
12+
o["default"] = v;
13+
});
14+
var __importStar = (this && this.__importStar) || function (mod) {
15+
if (mod && mod.__esModule) return mod;
16+
var result = {};
17+
if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18+
__setModuleDefault(result, mod);
19+
return result;
20+
};
221
var __importDefault = (this && this.__importDefault) || function (mod) {
322
return (mod && mod.__esModule) ? mod : { "default": mod };
423
};
524
Object.defineProperty(exports, "__esModule", { value: true });
25+
const node_libcurl_1 = require("node-libcurl");
626
const websiteBenchTools_1 = __importDefault(require("./websiteBenchTools"));
27+
const qObj = __importStar(require("q"));
728
class WebsiteBenchBrowser {
829
constructor(browserObj, configObj, logObj) {
930
this.toolsObj = new websiteBenchTools_1.default();
@@ -13,7 +34,7 @@ class WebsiteBenchBrowser {
1334
this.configObj = configObj;
1435
this.logObj = logObj;
1536
}
16-
async processPage(websiteEntry) {
37+
async processPageWithBrowser(websiteEntry) {
1738
const webUrl = websiteEntry.siteUrl;
1839
const reqTimeout = websiteEntry.checkInterval - 1;
1940
let perfData = null;
@@ -87,6 +108,85 @@ class WebsiteBenchBrowser {
87108
};
88109
return perfData;
89110
}
111+
async processPageWithCurl(websiteEntry) {
112+
return new Promise((retFunc, rejFunc) => {
113+
const webUrl = websiteEntry.siteUrl;
114+
const reqTimeout = websiteEntry.checkInterval - 1;
115+
const promiseArray = [];
116+
let userAgent;
117+
let perfData = null;
118+
const perfDataTotal = {
119+
totalDurTime: 0,
120+
connectTime: 0,
121+
dnsTime: 0,
122+
ttfbTime: 0,
123+
preTransfer: 0,
124+
tlsHandshake: 0,
125+
statusCode: 0,
126+
statusCodes: []
127+
};
128+
if (this.configObj.userAgent) {
129+
userAgent = this.configObj.userAgent;
130+
}
131+
else {
132+
let browserUserAgent = node_libcurl_1.Curl.defaultUserAgent;
133+
userAgent = `${browserUserAgent} websiteBench/${this.configObj.versionNum}`;
134+
}
135+
for (let runCount = 0; runCount < this.numOfRetries; runCount++) {
136+
this.logObj.debug(`Starting performance data collection for ${webUrl} (Run: ${runCount})...`);
137+
const deferObj = qObj.defer();
138+
const curlObj = new node_libcurl_1.Curl();
139+
curlObj.setOpt('URL', webUrl);
140+
curlObj.setOpt('TIMEOUT', reqTimeout);
141+
curlObj.setOpt('USERAGENT', userAgent);
142+
curlObj.setOpt('DNS_SHUFFLE_ADDRESSES', true);
143+
curlObj.setOpt('SSL_VERIFYHOST', this.configObj.ignoreSslErrors === true ? false : true);
144+
curlObj.on('end', (statusCode, resData, resHeader, curlInstance) => {
145+
const tempPerf = {
146+
runNumber: runCount,
147+
totalDurTime: curlInstance.getInfo('TOTAL_TIME_T') / 1000,
148+
dnsTime: curlInstance.getInfo('NAMELOOKUP_TIME_T') / 1000,
149+
tlsHandshake: curlInstance.getInfo('APPCONNECT_TIME_T') / 1000,
150+
ttfbTime: curlInstance.getInfo('STARTTRANSFER_TIME_T') / 1000,
151+
preTransfer: curlInstance.getInfo('PRETRANSFER_TIME_T') / 1000,
152+
connectTime: curlInstance.getInfo('CONNECT_TIME_T') / 1000,
153+
statusCode: statusCode
154+
};
155+
deferObj.resolve(tempPerf);
156+
curlInstance.close();
157+
});
158+
curlObj.on('error', (errorObj) => {
159+
this.logObj.error(`Unable to fetch page via cURL: ${errorObj.message}`);
160+
this.logObj.debug(`Completed performance data collection with error for ${webUrl} (Run: ${runCount})...`);
161+
});
162+
curlObj.perform();
163+
promiseArray.push(deferObj.promise);
164+
}
165+
qObj.all(promiseArray).then(resPromise => {
166+
resPromise.forEach(curlPromise => {
167+
perfDataTotal.totalDurTime += curlPromise.totalDurTime;
168+
perfDataTotal.connectTime += curlPromise.connectTime;
169+
perfDataTotal.dnsTime += curlPromise.dnsTime;
170+
perfDataTotal.ttfbTime += curlPromise.ttfbTime;
171+
perfDataTotal.tlsHandshake += curlPromise.tlsHandshake;
172+
perfDataTotal.preTransfer += curlPromise.preTransfer;
173+
perfDataTotal.statusCodes.push(curlPromise.statusCode);
174+
this.logObj.debug(`Completed performance data collection for ${webUrl} (Run: ${curlPromise.runNumber})...`);
175+
});
176+
}).finally(() => {
177+
perfData = {
178+
totalDurTime: (perfDataTotal.totalDurTime / this.numOfRetries),
179+
connectTime: (perfDataTotal.connectTime / this.numOfRetries),
180+
dnsTime: (perfDataTotal.dnsTime / this.numOfRetries),
181+
ttfbTime: (perfDataTotal.ttfbTime / this.numOfRetries),
182+
tlsHandshake: (perfDataTotal.tlsHandshake / this.numOfRetries),
183+
preTransfer: (perfDataTotal.preTransfer / this.numOfRetries),
184+
};
185+
perfData.statusCodesString = perfDataTotal.statusCodes.join(':');
186+
retFunc(perfData);
187+
});
188+
});
189+
}
90190
async eventTriggered(eventObj) {
91191
if (this.toolsObj.eventIsDialog(eventObj)) {
92192
eventObj.dismiss();

dist/lib/websiteBenchConfig.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export default class WebsiteBenchConfig {
44
private _configObj;
55
private _versionNum;
66
private _allowCaching;
7+
private _ignoreSslErrors;
78
private _logResourceErrors;
89
private _maxConcurrentJobs;
910
private _minCheckInterval;

dist/lib/websiteBenchConfig.d.ts.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/lib/websiteBenchConfig.js

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ const process_1 = require("process");
55
class WebsiteBenchConfig {
66
constructor(confFiles, logObj) {
77
this._configObj = {};
8-
this._versionNum = '1.2.3';
8+
this._versionNum = '1.3.2';
99
this._allowCaching = false;
10+
this._ignoreSslErrors = false;
1011
this._logResourceErrors = false;
1112
this._maxConcurrentJobs = 5;
1213
this._minCheckInterval = 30;
@@ -18,7 +19,8 @@ class WebsiteBenchConfig {
1819
allowCaching: this._allowCaching,
1920
maxConcurrentJobs: this._maxConcurrentJobs,
2021
logResErrors: this._logResourceErrors,
21-
versionNum: this._versionNum,
22+
ignoreSslErrors: this._ignoreSslErrors,
23+
versionNum: this._versionNum
2224
}, confFileData);
2325
this._configObj.influxDb = { ...this._configObj.influxDb, ...secretFileData.influxDb };
2426
try {
@@ -46,7 +48,7 @@ class WebsiteBenchConfig {
4648
return this._configObj;
4749
}
4850
checkMandatory() {
49-
const mandatoryProps = ['maxConcurrentJobs', 'allowCaching', 'websiteList', 'influxDb'];
51+
const mandatoryProps = ['maxConcurrentJobs', 'allowCaching', 'websiteList', 'influxDb', 'instanceName'];
5052
const mandatoryInflux = ['hostname', 'database', 'username', 'password'];
5153
let missingProps = null;
5254
for (const objProp of mandatoryProps) {
@@ -87,6 +89,11 @@ class WebsiteBenchConfig {
8789
configError.errorProperty = 'websiteList => siteUrl';
8890
configError.errorMessage = 'Not all website list entries have a "siteUrl" property or the value is not a string';
8991
}
92+
if ('checkType' in websiteEntry && typeof websiteEntry.checkType !== 'string') {
93+
configError.hasError = true;
94+
configError.errorProperty = 'websiteList => checkType';
95+
configError.errorMessage = 'Value of "checkType" is not a string';
96+
}
9097
if (!('checkInterval' in websiteEntry) || typeof websiteEntry.checkInterval !== 'number') {
9198
configError.hasError = true;
9299
configError.errorProperty = 'websiteList => checkInterval';
@@ -107,6 +114,11 @@ class WebsiteBenchConfig {
107114
configError.errorProperty = 'siteUrl';
108115
configError.errorMessage = `"siteUrl" of website entry "${websiteEntry.siteName}" cannot be empty`;
109116
}
117+
if ('checkType' in websiteEntry && (websiteEntry.checkType.toLowerCase() !== 'browser' && websiteEntry.checkType.toLowerCase() !== 'curl')) {
118+
configError.hasError = true;
119+
configError.errorProperty = 'checkType';
120+
configError.errorMessage = `"checkType" of website entry "${websiteEntry.siteName}" has to be either "browser" or "curl"`;
121+
}
110122
try {
111123
new URL(websiteEntry.siteUrl);
112124
}

0 commit comments

Comments
 (0)