@crawlee/core 3.9.3-beta.47 → 3.9.3-beta.49
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/crawlers/error_snapshotter.d.ts +56 -0
- package/crawlers/error_snapshotter.d.ts.map +1 -0
- package/crawlers/error_snapshotter.js +141 -0
- package/crawlers/error_snapshotter.js.map +1 -0
- package/crawlers/error_tracker.d.ts +54 -0
- package/crawlers/error_tracker.d.ts.map +1 -0
- package/crawlers/error_tracker.js +323 -0
- package/crawlers/error_tracker.js.map +1 -0
- package/crawlers/index.d.ts +2 -0
- package/crawlers/index.d.ts.map +1 -1
- package/crawlers/index.js +2 -0
- package/crawlers/index.js.map +1 -1
- package/crawlers/statistics.d.ts +6 -1
- package/crawlers/statistics.d.ts.map +1 -1
- package/crawlers/statistics.js +7 -4
- package/crawlers/statistics.js.map +1 -1
- package/index.mjs +2 -0
- package/package.json +5 -5
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { ErrnoException } from './error_tracker';
|
|
2
|
+
import type { CrawlingContext } from '../crawlers/crawler_commons';
|
|
3
|
+
import type { KeyValueStore } from '../storages';
|
|
4
|
+
interface BrowserCrawlingContext {
|
|
5
|
+
saveSnapshot: (options: {
|
|
6
|
+
key: string;
|
|
7
|
+
}) => Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
export interface SnapshotResult {
|
|
10
|
+
screenshotFileName?: string;
|
|
11
|
+
htmlFileName?: string;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* ErrorSnapshotter class is used to capture a screenshot of the page and a snapshot of the HTML when an error occurs during web crawling.
|
|
15
|
+
*
|
|
16
|
+
* This functionality is opt-in, and can be enabled via the crawler options:
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* const crawler = new BasicCrawler({
|
|
20
|
+
* // ...
|
|
21
|
+
* statisticsOptions: {
|
|
22
|
+
* saveErrorSnapshots: true,
|
|
23
|
+
* },
|
|
24
|
+
* });
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare class ErrorSnapshotter {
|
|
28
|
+
static readonly MAX_ERROR_CHARACTERS = 30;
|
|
29
|
+
static readonly MAX_HASH_LENGTH = 30;
|
|
30
|
+
static readonly MAX_FILENAME_LENGTH = 250;
|
|
31
|
+
static readonly BASE_MESSAGE = "An error occurred";
|
|
32
|
+
static readonly SNAPSHOT_PREFIX = "ERROR_SNAPSHOT";
|
|
33
|
+
/**
|
|
34
|
+
* Capture a snapshot of the error context.
|
|
35
|
+
*/
|
|
36
|
+
captureSnapshot(error: ErrnoException, context: CrawlingContext): Promise<{
|
|
37
|
+
screenshotFileName?: string;
|
|
38
|
+
htmlFileName?: string;
|
|
39
|
+
}>;
|
|
40
|
+
/**
|
|
41
|
+
* Captures a snapshot of the current page using the context.saveSnapshot function.
|
|
42
|
+
* This function is applicable for browser contexts only.
|
|
43
|
+
* Returns an object containing the filenames of the screenshot and HTML file.
|
|
44
|
+
*/
|
|
45
|
+
contextCaptureSnapshot(context: BrowserCrawlingContext, fileName: string): Promise<SnapshotResult | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* Save the HTML snapshot of the page, and return the fileName with the extension.
|
|
48
|
+
*/
|
|
49
|
+
saveHTMLSnapshot(html: string, keyValueStore: KeyValueStore, fileName: string): Promise<string | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* Generate a unique fileName for each error snapshot.
|
|
52
|
+
*/
|
|
53
|
+
generateFilename(error: ErrnoException): string;
|
|
54
|
+
}
|
|
55
|
+
export {};
|
|
56
|
+
//# sourceMappingURL=error_snapshotter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_snapshotter.d.ts","sourceRoot":"","sources":["../../src/crawlers/error_snapshotter.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,UAAU,sBAAsB;IAC5B,YAAY,EAAE,CAAC,OAAO,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC7D;AAMD,MAAM,WAAW,cAAc;IAC3B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB;IACzB,MAAM,CAAC,QAAQ,CAAC,oBAAoB,MAAM;IAC1C,MAAM,CAAC,QAAQ,CAAC,eAAe,MAAM;IACrC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,OAAO;IAC1C,MAAM,CAAC,QAAQ,CAAC,YAAY,uBAAuB;IACnD,MAAM,CAAC,QAAQ,CAAC,eAAe,oBAAoB;IAEnD;;OAEG;IACG,eAAe,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC;QAAE,kBAAkB,CAAC,EAAE,MAAM,CAAC;QAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IA6CvI;;;;OAIG;IACG,sBAAsB,CAAC,OAAO,EAAE,sBAAsB,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,GAAG,SAAS,CAAC;IAYpH;;OAEG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;IASjH;;OAEG;IACH,gBAAgB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM;CAoBlD"}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ErrorSnapshotter = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_crypto_1 = tslib_1.__importDefault(require("node:crypto"));
|
|
6
|
+
/**
|
|
7
|
+
* ErrorSnapshotter class is used to capture a screenshot of the page and a snapshot of the HTML when an error occurs during web crawling.
|
|
8
|
+
*
|
|
9
|
+
* This functionality is opt-in, and can be enabled via the crawler options:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const crawler = new BasicCrawler({
|
|
13
|
+
* // ...
|
|
14
|
+
* statisticsOptions: {
|
|
15
|
+
* saveErrorSnapshots: true,
|
|
16
|
+
* },
|
|
17
|
+
* });
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
class ErrorSnapshotter {
|
|
21
|
+
/**
|
|
22
|
+
* Capture a snapshot of the error context.
|
|
23
|
+
*/
|
|
24
|
+
async captureSnapshot(error, context) {
|
|
25
|
+
try {
|
|
26
|
+
const page = context?.page;
|
|
27
|
+
const body = context?.body;
|
|
28
|
+
const keyValueStore = await context?.getKeyValueStore();
|
|
29
|
+
// If the key-value store is not available, or the body and page are not available, return empty filenames
|
|
30
|
+
if (!keyValueStore || (!body && !page)) {
|
|
31
|
+
return {};
|
|
32
|
+
}
|
|
33
|
+
const fileName = this.generateFilename(error);
|
|
34
|
+
let screenshotFileName;
|
|
35
|
+
let htmlFileName;
|
|
36
|
+
if (page) {
|
|
37
|
+
const capturedFiles = await this.contextCaptureSnapshot(context, fileName);
|
|
38
|
+
if (capturedFiles) {
|
|
39
|
+
screenshotFileName = capturedFiles.screenshotFileName;
|
|
40
|
+
htmlFileName = capturedFiles.htmlFileName;
|
|
41
|
+
}
|
|
42
|
+
// If the snapshot for browsers failed to capture the HTML, try to capture it from the page content
|
|
43
|
+
if (!htmlFileName) {
|
|
44
|
+
const html = await page.content();
|
|
45
|
+
htmlFileName = html ? await this.saveHTMLSnapshot(html, keyValueStore, fileName) : undefined;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
else if (typeof body === 'string') { // for non-browser contexts
|
|
49
|
+
htmlFileName = await this.saveHTMLSnapshot(body, keyValueStore, fileName);
|
|
50
|
+
}
|
|
51
|
+
return {
|
|
52
|
+
screenshotFileName,
|
|
53
|
+
htmlFileName,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Captures a snapshot of the current page using the context.saveSnapshot function.
|
|
62
|
+
* This function is applicable for browser contexts only.
|
|
63
|
+
* Returns an object containing the filenames of the screenshot and HTML file.
|
|
64
|
+
*/
|
|
65
|
+
async contextCaptureSnapshot(context, fileName) {
|
|
66
|
+
try {
|
|
67
|
+
await context.saveSnapshot({ key: fileName });
|
|
68
|
+
return {
|
|
69
|
+
screenshotFileName: `${fileName}.jpg`,
|
|
70
|
+
htmlFileName: `${fileName}.html`,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Save the HTML snapshot of the page, and return the fileName with the extension.
|
|
79
|
+
*/
|
|
80
|
+
async saveHTMLSnapshot(html, keyValueStore, fileName) {
|
|
81
|
+
try {
|
|
82
|
+
await keyValueStore.setValue(fileName, html, { contentType: 'text/html' });
|
|
83
|
+
return `${fileName}.html`;
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generate a unique fileName for each error snapshot.
|
|
91
|
+
*/
|
|
92
|
+
generateFilename(error) {
|
|
93
|
+
const { SNAPSHOT_PREFIX, BASE_MESSAGE, MAX_HASH_LENGTH, MAX_ERROR_CHARACTERS, MAX_FILENAME_LENGTH } = ErrorSnapshotter;
|
|
94
|
+
// Create a hash of the error stack trace
|
|
95
|
+
const errorStackHash = node_crypto_1.default.createHash('sha1').update(error.stack || error.message || '').digest('hex').slice(0, MAX_HASH_LENGTH);
|
|
96
|
+
const errorMessagePrefix = (error.message || BASE_MESSAGE).slice(0, MAX_ERROR_CHARACTERS).trim();
|
|
97
|
+
/**
|
|
98
|
+
* Remove non-word characters from the start and end of a string.
|
|
99
|
+
*/
|
|
100
|
+
const sanitizeString = (str) => {
|
|
101
|
+
return str.replace(/^\W+|\W+$/g, '');
|
|
102
|
+
};
|
|
103
|
+
// Generate fileName and remove disallowed characters
|
|
104
|
+
const fileName = `${SNAPSHOT_PREFIX}_${sanitizeString(errorStackHash)}_${sanitizeString(errorMessagePrefix)}`
|
|
105
|
+
.replace(/\W+/g, '-') // Replace non-word characters with a dash
|
|
106
|
+
.slice(0, MAX_FILENAME_LENGTH);
|
|
107
|
+
return fileName;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.ErrorSnapshotter = ErrorSnapshotter;
|
|
111
|
+
Object.defineProperty(ErrorSnapshotter, "MAX_ERROR_CHARACTERS", {
|
|
112
|
+
enumerable: true,
|
|
113
|
+
configurable: true,
|
|
114
|
+
writable: true,
|
|
115
|
+
value: 30
|
|
116
|
+
});
|
|
117
|
+
Object.defineProperty(ErrorSnapshotter, "MAX_HASH_LENGTH", {
|
|
118
|
+
enumerable: true,
|
|
119
|
+
configurable: true,
|
|
120
|
+
writable: true,
|
|
121
|
+
value: 30
|
|
122
|
+
});
|
|
123
|
+
Object.defineProperty(ErrorSnapshotter, "MAX_FILENAME_LENGTH", {
|
|
124
|
+
enumerable: true,
|
|
125
|
+
configurable: true,
|
|
126
|
+
writable: true,
|
|
127
|
+
value: 250
|
|
128
|
+
});
|
|
129
|
+
Object.defineProperty(ErrorSnapshotter, "BASE_MESSAGE", {
|
|
130
|
+
enumerable: true,
|
|
131
|
+
configurable: true,
|
|
132
|
+
writable: true,
|
|
133
|
+
value: 'An error occurred'
|
|
134
|
+
});
|
|
135
|
+
Object.defineProperty(ErrorSnapshotter, "SNAPSHOT_PREFIX", {
|
|
136
|
+
enumerable: true,
|
|
137
|
+
configurable: true,
|
|
138
|
+
writable: true,
|
|
139
|
+
value: 'ERROR_SNAPSHOT'
|
|
140
|
+
});
|
|
141
|
+
//# sourceMappingURL=error_snapshotter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_snapshotter.js","sourceRoot":"","sources":["../../src/crawlers/error_snapshotter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { ErrorSnapshotter } from './error_snapshotter';
|
|
2
|
+
import type { CrawlingContext } from '../crawlers/crawler_commons';
|
|
3
|
+
/**
|
|
4
|
+
* Node.js Error interface
|
|
5
|
+
*/
|
|
6
|
+
export interface ErrnoException extends Error {
|
|
7
|
+
errno?: number;
|
|
8
|
+
code?: string | number;
|
|
9
|
+
path?: string;
|
|
10
|
+
syscall?: string;
|
|
11
|
+
cause?: any;
|
|
12
|
+
}
|
|
13
|
+
export interface ErrorTrackerOptions {
|
|
14
|
+
showErrorCode: boolean;
|
|
15
|
+
showErrorName: boolean;
|
|
16
|
+
showStackTrace: boolean;
|
|
17
|
+
showFullStack: boolean;
|
|
18
|
+
showErrorMessage: boolean;
|
|
19
|
+
showFullMessage: boolean;
|
|
20
|
+
saveErrorSnapshots: boolean;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* This class tracks errors and computes a summary of information like:
|
|
24
|
+
* - where the errors happened
|
|
25
|
+
* - what the error names are
|
|
26
|
+
* - what the error codes are
|
|
27
|
+
* - what is the general error message
|
|
28
|
+
*
|
|
29
|
+
* This is extremely useful when there are dynamic error messages, such as argument validation.
|
|
30
|
+
*
|
|
31
|
+
* Since the structure of the `tracker.result` object differs when using different options,
|
|
32
|
+
* it's typed as `Record<string, unknown>`. The most deep object has a `count` property, which is a number.
|
|
33
|
+
*
|
|
34
|
+
* It's possible to get the total amount of errors via the `tracker.total` property.
|
|
35
|
+
*/
|
|
36
|
+
export declare class ErrorTracker {
|
|
37
|
+
#private;
|
|
38
|
+
result: Record<string, unknown>;
|
|
39
|
+
total: number;
|
|
40
|
+
errorSnapshotter?: ErrorSnapshotter;
|
|
41
|
+
constructor(options?: Partial<ErrorTrackerOptions>);
|
|
42
|
+
private updateGroup;
|
|
43
|
+
add(error: ErrnoException): void;
|
|
44
|
+
/**
|
|
45
|
+
* This method is async, because it captures a snapshot of the error context.
|
|
46
|
+
* We added this new method to avoid breaking changes.
|
|
47
|
+
*/
|
|
48
|
+
addAsync(error: ErrnoException, context?: CrawlingContext): Promise<void>;
|
|
49
|
+
getUniqueErrorCount(): number;
|
|
50
|
+
getMostPopularErrors(count: number): [number, string[]][];
|
|
51
|
+
captureSnapshot(storage: Record<string, unknown>, error: ErrnoException, context: CrawlingContext): Promise<void>;
|
|
52
|
+
reset(): void;
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=error_tracker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_tracker.d.ts","sourceRoot":"","sources":["../../src/crawlers/error_tracker.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACvD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAEnE;;GAEG;AACH,MAAM,WAAW,cAAe,SAAQ,KAAK;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,GAAG,CAAC;CACf;AAED,MAAM,WAAW,mBAAmB;IAChC,aAAa,EAAE,OAAO,CAAC;IACvB,aAAa,EAAE,OAAO,CAAC;IACvB,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,eAAe,EAAE,OAAO,CAAC;IACzB,kBAAkB,EAAE,OAAO,CAAC;CAC/B;AAoPD;;;;;;;;;;;;;GAaG;AACH,qBAAa,YAAY;;IAGrB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEhC,KAAK,EAAE,MAAM,CAAC;IAEd,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;gBAExB,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IAoBtD,OAAO,CAAC,WAAW;IAwBnB,GAAG,CAAC,KAAK,EAAE,cAAc;IAUzB;;;OAGG;IACG,QAAQ,CAAC,KAAK,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,eAAe;IAe/D,mBAAmB;IAoBnB,oBAAoB,CAAC,KAAK,EAAE,MAAM;IAoB5B,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,eAAe;IAWvG,KAAK;CAOR"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var _ErrorTracker_options;
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ErrorTracker = void 0;
|
|
5
|
+
const tslib_1 = require("tslib");
|
|
6
|
+
const node_util_1 = require("node:util");
|
|
7
|
+
const error_snapshotter_1 = require("./error_snapshotter");
|
|
8
|
+
const extractPathFromStackTraceLine = (line) => {
|
|
9
|
+
const lastStartingRoundBracketIndex = line.lastIndexOf('(');
|
|
10
|
+
if (lastStartingRoundBracketIndex !== -1) {
|
|
11
|
+
const closingRoundBracketIndex = line.indexOf(')', lastStartingRoundBracketIndex);
|
|
12
|
+
if (closingRoundBracketIndex !== -1) {
|
|
13
|
+
return line.slice(lastStartingRoundBracketIndex + 1, closingRoundBracketIndex);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return line;
|
|
17
|
+
};
|
|
18
|
+
// https://v8.dev/docs/stack-trace-api#appendix%3A-stack-trace-format
|
|
19
|
+
const getPathFromStackTrace = (stack) => {
|
|
20
|
+
for (const line of stack) {
|
|
21
|
+
const path = extractPathFromStackTraceLine(line);
|
|
22
|
+
if (path.startsWith('node:')
|
|
23
|
+
|| path.includes('/node_modules/')
|
|
24
|
+
|| path.includes('\\node_modules\\')) {
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
return path;
|
|
28
|
+
}
|
|
29
|
+
return extractPathFromStackTraceLine(stack[0]);
|
|
30
|
+
};
|
|
31
|
+
const getStackTraceGroup = (error, storage, showFullStack) => {
|
|
32
|
+
const stack = error.stack?.split('\n').map((line) => line.trim());
|
|
33
|
+
let sliceAt = -1;
|
|
34
|
+
if (stack) {
|
|
35
|
+
for (let i = 0; i < stack.length; i++) {
|
|
36
|
+
if (stack[i].startsWith('at ') || stack[i].startsWith('eval at ')) {
|
|
37
|
+
sliceAt = i;
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let normalizedStackTrace = null;
|
|
43
|
+
if (sliceAt !== -1) {
|
|
44
|
+
normalizedStackTrace = showFullStack ? stack.slice(sliceAt).map((x) => x.trim()).join('\n') : getPathFromStackTrace(stack.slice(sliceAt));
|
|
45
|
+
}
|
|
46
|
+
if (!normalizedStackTrace) {
|
|
47
|
+
normalizedStackTrace = 'missing stack trace';
|
|
48
|
+
}
|
|
49
|
+
if (!(normalizedStackTrace in storage)) {
|
|
50
|
+
storage[normalizedStackTrace] = Object.create(null);
|
|
51
|
+
}
|
|
52
|
+
return storage[normalizedStackTrace];
|
|
53
|
+
};
|
|
54
|
+
const getErrorCodeGroup = (error, storage) => {
|
|
55
|
+
let { code } = error;
|
|
56
|
+
if (code === undefined) {
|
|
57
|
+
code = 'missing error code';
|
|
58
|
+
}
|
|
59
|
+
if (!(code in storage)) {
|
|
60
|
+
storage[code] = Object.create(null);
|
|
61
|
+
}
|
|
62
|
+
return storage[String(code)];
|
|
63
|
+
};
|
|
64
|
+
const getErrorNameGroup = (error, storage) => {
|
|
65
|
+
const { name } = error;
|
|
66
|
+
if (!(name in storage)) {
|
|
67
|
+
storage[name] = Object.create(null);
|
|
68
|
+
}
|
|
69
|
+
return storage[name];
|
|
70
|
+
};
|
|
71
|
+
const findBiggestWordIntersection = (a, b) => {
|
|
72
|
+
let maxStreak = 0;
|
|
73
|
+
let bStreakIndex = -1;
|
|
74
|
+
let aStreakIndex = -1;
|
|
75
|
+
for (let aIndex = 0; aIndex < a.length; aIndex++) {
|
|
76
|
+
let bIndex = -1;
|
|
77
|
+
do {
|
|
78
|
+
let aWalkIndex = aIndex;
|
|
79
|
+
bIndex = b.indexOf(a[aIndex], bIndex + 1);
|
|
80
|
+
let bWalkIndex = bIndex;
|
|
81
|
+
let streak = 0;
|
|
82
|
+
while (aWalkIndex < a.length && bWalkIndex < b.length && b[bWalkIndex++] === a[aWalkIndex++]) {
|
|
83
|
+
streak++;
|
|
84
|
+
}
|
|
85
|
+
if (streak > maxStreak) {
|
|
86
|
+
maxStreak = streak;
|
|
87
|
+
aStreakIndex = aIndex;
|
|
88
|
+
bStreakIndex = bIndex;
|
|
89
|
+
}
|
|
90
|
+
} while (bIndex !== -1);
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
maxStreak,
|
|
94
|
+
aStreakIndex,
|
|
95
|
+
bStreakIndex,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
const arrayCount = (array, target) => {
|
|
99
|
+
let result = 0;
|
|
100
|
+
for (const item of array) {
|
|
101
|
+
if (item === target) {
|
|
102
|
+
result++;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
};
|
|
107
|
+
const calculatePlaceholder = (a, b) => {
|
|
108
|
+
const { maxStreak, aStreakIndex, bStreakIndex } = findBiggestWordIntersection(a, b);
|
|
109
|
+
if (maxStreak === 0) {
|
|
110
|
+
return ['_'];
|
|
111
|
+
}
|
|
112
|
+
const leftA = a.slice(0, aStreakIndex);
|
|
113
|
+
const leftB = b.slice(0, bStreakIndex);
|
|
114
|
+
const rightA = a.slice(aStreakIndex + maxStreak);
|
|
115
|
+
const rightB = b.slice(bStreakIndex + maxStreak);
|
|
116
|
+
const output = [];
|
|
117
|
+
if (leftA.length !== 0 || leftB.length !== 0) {
|
|
118
|
+
output.push(...calculatePlaceholder(leftA, leftB));
|
|
119
|
+
}
|
|
120
|
+
output.push(...a.slice(aStreakIndex, aStreakIndex + maxStreak));
|
|
121
|
+
if (rightA.length !== 0 || rightB.length !== 0) {
|
|
122
|
+
output.push(...calculatePlaceholder(rightA, rightB));
|
|
123
|
+
}
|
|
124
|
+
return output;
|
|
125
|
+
};
|
|
126
|
+
const normalizedCalculatePlaceholder = (a, b) => {
|
|
127
|
+
const output = calculatePlaceholder(a, b);
|
|
128
|
+
// We can't be too general
|
|
129
|
+
if ((arrayCount(output, '_') / output.length) >= 0.5) {
|
|
130
|
+
return ['_'];
|
|
131
|
+
}
|
|
132
|
+
return output;
|
|
133
|
+
};
|
|
134
|
+
// Merge A (missing placeholders) into B (can contain placeholders but does not have to)
|
|
135
|
+
const mergeMessages = (a, b, storage) => {
|
|
136
|
+
const placeholder = normalizedCalculatePlaceholder(a.split(' '), b.split(' ')).join(' ');
|
|
137
|
+
if (placeholder === '_') {
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
const count = storage[a].count + storage[b].count;
|
|
141
|
+
delete storage[a];
|
|
142
|
+
delete storage[b];
|
|
143
|
+
storage[placeholder] = Object.assign(Object.create(null), {
|
|
144
|
+
count,
|
|
145
|
+
});
|
|
146
|
+
return placeholder;
|
|
147
|
+
};
|
|
148
|
+
const getErrorMessageGroup = (error, storage, showFullMessage) => {
|
|
149
|
+
let { message } = error;
|
|
150
|
+
if (!message) {
|
|
151
|
+
try {
|
|
152
|
+
message = typeof error === 'string' ? error : `Unknown error message. Received non-error object: ${JSON.stringify(error)}`;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
message = `Unknown error message. Received non-error object, and could not stringify it: ${(0, node_util_1.inspect)(error, { depth: 0 })}`;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
if (!showFullMessage) {
|
|
159
|
+
const newLineIndex = message.indexOf('\n');
|
|
160
|
+
message = message.slice(0, newLineIndex === -1 ? undefined : newLineIndex);
|
|
161
|
+
}
|
|
162
|
+
if (!(message in storage)) {
|
|
163
|
+
storage[message] = Object.assign(Object.create(null), {
|
|
164
|
+
count: 0,
|
|
165
|
+
});
|
|
166
|
+
// This actually safe, since we Object.create(null) so no prototype pollution can happen.
|
|
167
|
+
// eslint-disable-next-line no-restricted-syntax, guard-for-in
|
|
168
|
+
for (const existingMessage in storage) {
|
|
169
|
+
const newMessage = mergeMessages(message, existingMessage, storage);
|
|
170
|
+
if (newMessage) {
|
|
171
|
+
message = newMessage;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return storage[message];
|
|
177
|
+
};
|
|
178
|
+
const increaseCount = (group) => {
|
|
179
|
+
if (!('count' in group)) {
|
|
180
|
+
// In case users don't want to display error message
|
|
181
|
+
group.count = 0;
|
|
182
|
+
}
|
|
183
|
+
group.count++;
|
|
184
|
+
};
|
|
185
|
+
/**
|
|
186
|
+
* This class tracks errors and computes a summary of information like:
|
|
187
|
+
* - where the errors happened
|
|
188
|
+
* - what the error names are
|
|
189
|
+
* - what the error codes are
|
|
190
|
+
* - what is the general error message
|
|
191
|
+
*
|
|
192
|
+
* This is extremely useful when there are dynamic error messages, such as argument validation.
|
|
193
|
+
*
|
|
194
|
+
* Since the structure of the `tracker.result` object differs when using different options,
|
|
195
|
+
* it's typed as `Record<string, unknown>`. The most deep object has a `count` property, which is a number.
|
|
196
|
+
*
|
|
197
|
+
* It's possible to get the total amount of errors via the `tracker.total` property.
|
|
198
|
+
*/
|
|
199
|
+
class ErrorTracker {
|
|
200
|
+
constructor(options = {}) {
|
|
201
|
+
_ErrorTracker_options.set(this, void 0);
|
|
202
|
+
Object.defineProperty(this, "result", {
|
|
203
|
+
enumerable: true,
|
|
204
|
+
configurable: true,
|
|
205
|
+
writable: true,
|
|
206
|
+
value: void 0
|
|
207
|
+
});
|
|
208
|
+
Object.defineProperty(this, "total", {
|
|
209
|
+
enumerable: true,
|
|
210
|
+
configurable: true,
|
|
211
|
+
writable: true,
|
|
212
|
+
value: void 0
|
|
213
|
+
});
|
|
214
|
+
Object.defineProperty(this, "errorSnapshotter", {
|
|
215
|
+
enumerable: true,
|
|
216
|
+
configurable: true,
|
|
217
|
+
writable: true,
|
|
218
|
+
value: void 0
|
|
219
|
+
});
|
|
220
|
+
tslib_1.__classPrivateFieldSet(this, _ErrorTracker_options, {
|
|
221
|
+
showErrorCode: true,
|
|
222
|
+
showErrorName: true,
|
|
223
|
+
showStackTrace: true,
|
|
224
|
+
showFullStack: false,
|
|
225
|
+
showErrorMessage: true,
|
|
226
|
+
showFullMessage: false,
|
|
227
|
+
saveErrorSnapshots: false,
|
|
228
|
+
...options,
|
|
229
|
+
}, "f");
|
|
230
|
+
if (tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").saveErrorSnapshots) {
|
|
231
|
+
this.errorSnapshotter = new error_snapshotter_1.ErrorSnapshotter();
|
|
232
|
+
}
|
|
233
|
+
this.result = Object.create(null);
|
|
234
|
+
this.total = 0;
|
|
235
|
+
}
|
|
236
|
+
updateGroup(error) {
|
|
237
|
+
let group = this.result;
|
|
238
|
+
if (tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showStackTrace) {
|
|
239
|
+
group = getStackTraceGroup(error, group, tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showFullStack);
|
|
240
|
+
}
|
|
241
|
+
if (tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showErrorCode) {
|
|
242
|
+
group = getErrorCodeGroup(error, group);
|
|
243
|
+
}
|
|
244
|
+
if (tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showErrorName) {
|
|
245
|
+
group = getErrorNameGroup(error, group);
|
|
246
|
+
}
|
|
247
|
+
if (tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showErrorMessage) {
|
|
248
|
+
group = getErrorMessageGroup(error, group, tslib_1.__classPrivateFieldGet(this, _ErrorTracker_options, "f").showFullMessage);
|
|
249
|
+
}
|
|
250
|
+
increaseCount(group);
|
|
251
|
+
return group;
|
|
252
|
+
}
|
|
253
|
+
add(error) {
|
|
254
|
+
this.total++;
|
|
255
|
+
this.updateGroup(error);
|
|
256
|
+
if (typeof error.cause === 'object' && error.cause !== null) {
|
|
257
|
+
this.add(error.cause);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* This method is async, because it captures a snapshot of the error context.
|
|
262
|
+
* We added this new method to avoid breaking changes.
|
|
263
|
+
*/
|
|
264
|
+
async addAsync(error, context) {
|
|
265
|
+
this.total++;
|
|
266
|
+
const group = this.updateGroup(error);
|
|
267
|
+
// Capture a snapshot (screenshot and HTML) on the first occurrence of an error
|
|
268
|
+
if (group.count === 1 && context) {
|
|
269
|
+
await this.captureSnapshot(group, error, context).catch(() => { });
|
|
270
|
+
}
|
|
271
|
+
if (typeof error.cause === 'object' && error.cause !== null) {
|
|
272
|
+
await this.addAsync(error.cause);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
getUniqueErrorCount() {
|
|
276
|
+
let count = 0;
|
|
277
|
+
const goDeeper = (group) => {
|
|
278
|
+
if ('count' in group) {
|
|
279
|
+
count++;
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
// eslint-disable-next-line guard-for-in, no-restricted-syntax
|
|
283
|
+
for (const key in group) {
|
|
284
|
+
goDeeper(group[key]);
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
goDeeper(this.result);
|
|
288
|
+
return count;
|
|
289
|
+
}
|
|
290
|
+
getMostPopularErrors(count) {
|
|
291
|
+
const result = [];
|
|
292
|
+
const goDeeper = (group, path) => {
|
|
293
|
+
if ('count' in group) {
|
|
294
|
+
result.push([group.count, path]);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
// eslint-disable-next-line guard-for-in, no-restricted-syntax
|
|
298
|
+
for (const key in group) {
|
|
299
|
+
goDeeper(group[key], [...path, key]);
|
|
300
|
+
}
|
|
301
|
+
};
|
|
302
|
+
goDeeper(this.result, []);
|
|
303
|
+
return result.sort((a, b) => b[0] - a[0]).slice(0, count);
|
|
304
|
+
}
|
|
305
|
+
async captureSnapshot(storage, error, context) {
|
|
306
|
+
if (!this.errorSnapshotter) {
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
const { screenshotFileName, htmlFileName } = await this.errorSnapshotter.captureSnapshot(error, context);
|
|
310
|
+
storage.firstErrorScreenshot = screenshotFileName;
|
|
311
|
+
storage.firstErrorHtml = htmlFileName;
|
|
312
|
+
}
|
|
313
|
+
reset() {
|
|
314
|
+
// This actually safe, since we Object.create(null) so no prototype pollution can happen.
|
|
315
|
+
// eslint-disable-next-line no-restricted-syntax, guard-for-in
|
|
316
|
+
for (const key in this.result) {
|
|
317
|
+
delete this.result[key];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
exports.ErrorTracker = ErrorTracker;
|
|
322
|
+
_ErrorTracker_options = new WeakMap();
|
|
323
|
+
//# sourceMappingURL=error_tracker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error_tracker.js","sourceRoot":"","sources":["../../src/crawlers/error_tracker.ts"],"names":[],"mappings":"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"}
|
package/crawlers/index.d.ts
CHANGED
package/crawlers/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crawlers/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/crawlers/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC"}
|
package/crawlers/index.js
CHANGED
|
@@ -5,4 +5,6 @@ tslib_1.__exportStar(require("./crawler_commons"), exports);
|
|
|
5
5
|
tslib_1.__exportStar(require("./crawler_extension"), exports);
|
|
6
6
|
tslib_1.__exportStar(require("./crawler_utils"), exports);
|
|
7
7
|
tslib_1.__exportStar(require("./statistics"), exports);
|
|
8
|
+
tslib_1.__exportStar(require("./error_tracker"), exports);
|
|
9
|
+
tslib_1.__exportStar(require("./error_snapshotter"), exports);
|
|
8
10
|
//# sourceMappingURL=index.js.map
|
package/crawlers/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crawlers/index.ts"],"names":[],"mappings":";;;AAAA,4DAAkC;AAClC,8DAAoC;AACpC,0DAAgC;AAChC,uDAA6B"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/crawlers/index.ts"],"names":[],"mappings":";;;AAAA,4DAAkC;AAClC,8DAAoC;AACpC,0DAAgC;AAChC,uDAA6B;AAC7B,0DAAgC;AAChC,8DAAoC"}
|
package/crawlers/statistics.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ErrorTracker } from '
|
|
1
|
+
import { ErrorTracker } from './error_tracker';
|
|
2
2
|
import { Configuration } from '../configuration';
|
|
3
3
|
import { KeyValueStore } from '../storages/key_value_store';
|
|
4
4
|
/**
|
|
@@ -166,6 +166,11 @@ export interface StatisticsOptions {
|
|
|
166
166
|
* Control how and when to persist the statistics.
|
|
167
167
|
*/
|
|
168
168
|
persistenceOptions?: PersistenceOptions;
|
|
169
|
+
/**
|
|
170
|
+
* Save HTML snapshot (and a screenshot if possible) when an error occurs.
|
|
171
|
+
* @default false
|
|
172
|
+
*/
|
|
173
|
+
saveErrorSnapshots?: boolean;
|
|
169
174
|
}
|
|
170
175
|
/**
|
|
171
176
|
* Format of the persisted stats
|