backtrace-node
Advanced tools
Comparing version 1.0.9 to 1.1.0
# Backtrace Node Release Notes | ||
## Version 1.1.0 | ||
- improved deduplication: the relative library path is used instead of absolute path for purposes of deduplication. | ||
- updated source-code integration - Backtrace will now include the relative path in stack trace. | ||
## Version 1.0.9 | ||
- axios client update | ||
## Version 1.0.8 | ||
- dependency updates | ||
## Version 1.0.7 | ||
- Full source map support, | ||
@@ -14,34 +22,48 @@ - readme updates | ||
## Version 1.0.6 30.10.2019 | ||
* Added sourcemap support to Backtrace-node | ||
* Fixed type attributes for report function | ||
* Changed a unit test result - removed console.log and check data instead. | ||
- Added sourcemap support to Backtrace-node | ||
- Fixed type attributes for report function | ||
- Changed a unit test result - removed console.log and check data instead. | ||
## Version 1.0.5 28.08.2019 | ||
* Fixed invalid source code line number | ||
- Fixed invalid source code line number | ||
## Version 1.0.4 26.08.2019 | ||
* Added attachments checks, | ||
* Added callback funciton to third parameter of send method, | ||
* Removed Backtrace stack frames from message error, | ||
- Added attachments checks, | ||
- Added callback funciton to third parameter of send method, | ||
- Removed Backtrace stack frames from message error, | ||
## Version 1.0.3 06.06.2019 | ||
* Added new events to event emitter: `new-report`, `unhandledRejection`, `uncaughtException`. `uncaughtException` and `unhandledRejection` events will be emited by library when library catch unhandled exception or unhandler promise rejection. `new-report` event will be emited when library create new `backtraceReport` object. | ||
- Added new events to event emitter: `new-report`, `unhandledRejection`, `uncaughtException`. `uncaughtException` and | ||
`unhandledRejection` events will be emited by library when library catch unhandled exception or unhandler promise | ||
rejection. `new-report` event will be emited when library create new `backtraceReport` object. | ||
## Version 1.0.2 05.06.2019 | ||
* Fixed arguments in callback function in report `send` method. | ||
- Fixed arguments in callback function in report `send` method. | ||
## Version 1.0.1 05.06.2019 | ||
* Added type definition for report `send` method | ||
- Added type definition for report `send` method | ||
## Version 1.0.0 04.06.2019 | ||
* `Backtrace-node` now supports TypeScript. We care about your applications that using Backtrace-Node library so we prepared compatible API for you. If you still want to use modern API please use `BacktraceClient` instead. | ||
* `Backtrace-node` options now support sampling and client rate limiting. | ||
- sampling allows you to drop random reports generated by your application depends on sampling value, | ||
- client rate limit allows you to set up client limit. By setting this value you will tell library how many reports per minute, client can send to Backtrace | ||
* `Backtrace-node` send methods accept new paramtere - `fileAttachment`. If you pass array of strings `backtrace-node` will try to read each file from hard drive and add this as attachment to `backtraceReport`. | ||
* `Backtrace-node` allows you to use `eventEmmiter` events! Now when you can use events like: `'before-send'`, `'after-send'` and others! | ||
* Modern Promise API is here! `Backtrace-node` allows you to use `async/await` syntax to send reports to Backtrace! | ||
* `reportSync` and `reportAsync` methods now returns `BacktraceResult` object that allows you to understand what happend with report. If you have connection/configuration problems `BacktraceResult` allows you to learn what happend inside library! | ||
* Backtrace prepare a lot sample application for you! If you want to learn how to use Backtrace in your nodejs application (no matter if you using JavaScript/TypeScript) please check examples directory! | ||
- `Backtrace-node` now supports TypeScript. We care about your applications that using Backtrace-Node library so we | ||
prepared compatible API for you. If you still want to use modern API please use `BacktraceClient` instead. | ||
- `Backtrace-node` options now support sampling and client rate limiting. | ||
- sampling allows you to drop random reports generated by your application depends on sampling value, | ||
- client rate limit allows you to set up client limit. By setting this value you will tell library how many reports | ||
per minute, client can send to Backtrace | ||
- `Backtrace-node` send methods accept new paramtere - `fileAttachment`. If you pass array of strings `backtrace-node` | ||
will try to read each file from hard drive and add this as attachment to `backtraceReport`. | ||
- `Backtrace-node` allows you to use `eventEmmiter` events! Now when you can use events like: `'before-send'`, | ||
`'after-send'` and others! | ||
- Modern Promise API is here! `Backtrace-node` allows you to use `async/await` syntax to send reports to Backtrace! | ||
- `reportSync` and `reportAsync` methods now returns `BacktraceResult` object that allows you to understand what happend | ||
with report. If you have connection/configuration problems `BacktraceResult` allows you to learn what happend inside | ||
library! | ||
- Backtrace prepare a lot sample application for you! If you want to learn how to use Backtrace in your nodejs | ||
application (no matter if you using JavaScript/TypeScript) please check examples directory! |
@@ -0,0 +0,0 @@ /// <reference types="node" /> |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -11,2 +11,3 @@ /// <reference types="node" /> | ||
options: BacktraceClientOptions; | ||
private _scopedAttributes; | ||
private _memorizedAttributes; | ||
@@ -70,3 +71,4 @@ private _backtraceApi; | ||
private registerPromiseHandler; | ||
private setupScopedAttributes; | ||
private registerGlobalHandler; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var clientRateLimit_1 = require("./clientRateLimit"); | ||
var events_1 = require("events"); | ||
var fs_1 = tslib_1.__importDefault(require("fs")); | ||
var path_1 = tslib_1.__importDefault(require("path")); | ||
var backtraceApi_1 = require("./backtraceApi"); | ||
var clientRateLimit_1 = require("./clientRateLimit"); | ||
var backtraceClientOptions_1 = require("./model/backtraceClientOptions"); | ||
@@ -17,2 +19,3 @@ var backtraceReport_1 = require("./model/backtraceReport"); | ||
var _this = _super.call(this) || this; | ||
_this._scopedAttributes = {}; | ||
_this._memorizedAttributes = {}; | ||
@@ -27,2 +30,3 @@ _this._symbolication = false; | ||
_this.registerHandlers(); | ||
_this.setupScopedAttributes(); | ||
return _this; | ||
@@ -199,3 +203,3 @@ } | ||
} | ||
return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, attributes), this.options.attributes), this.getMemorizedAttributes()); | ||
return tslib_1.__assign(tslib_1.__assign(tslib_1.__assign(tslib_1.__assign({}, attributes), this.options.attributes), this.getMemorizedAttributes()), this._scopedAttributes); | ||
}; | ||
@@ -227,2 +231,16 @@ BacktraceClient.prototype.getMemorizedAttributes = function () { | ||
}; | ||
BacktraceClient.prototype.setupScopedAttributes = function () { | ||
var applicationPackageJsonPath = path_1.default.join(process.cwd(), 'package.json'); | ||
if (!fs_1.default.existsSync(applicationPackageJsonPath)) { | ||
return; | ||
} | ||
var json = JSON.parse(fs_1.default.readFileSync(applicationPackageJsonPath, 'utf8')); | ||
this._scopedAttributes = { | ||
'application.version': json.version, | ||
application: json.name, | ||
main: json.main, | ||
description: json.description, | ||
author: typeof json.author === 'object' && json.author.name ? json.author.name : json.author, | ||
}; | ||
}; | ||
BacktraceClient.prototype.registerGlobalHandler = function (multipleExceptionListener) { | ||
@@ -229,0 +247,0 @@ var _this = this; |
@@ -0,0 +0,0 @@ import { BacktraceReport } from './model/backtraceReport'; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ /// <reference types="node" /> |
@@ -0,0 +0,0 @@ "use strict"; |
export declare function readMemoryInformation(): object; | ||
export declare function readProcessStatus(): object; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ import { BacktraceClient } from './backtraceClient'; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ export declare class BacktraceClientOptions implements IBacktraceClientOptions { |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -0,0 +0,0 @@ import { ISourceCode } from './sourceCode'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
//# sourceMappingURL=backtraceData.js.map |
@@ -10,2 +10,3 @@ import { IBacktraceData } from './backtraceData'; | ||
private attachments; | ||
private static machineId; | ||
set symbolication(symbolication: boolean); | ||
@@ -20,4 +21,4 @@ set symbolicationMap(symbolMap: Array<{ | ||
readonly langVersion: string; | ||
readonly agent: any; | ||
readonly agentVersion: any; | ||
readonly agent = "backtrace-node"; | ||
readonly agentVersion = "1.1.0"; | ||
readonly mainThread = "main"; | ||
@@ -24,0 +25,0 @@ classifiers: string[]; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
// tslint:disable-next-line: no-var-requires | ||
var packageJson = require('./../../package.json'); | ||
var crypto_1 = require("crypto"); | ||
@@ -44,5 +42,5 @@ var node_machine_id_1 = require("node-machine-id"); | ||
// Backtrace-ndoe name | ||
this.agent = packageJson.name; | ||
this.agent = 'backtrace-node'; | ||
// Backtrace-node version | ||
this.agentVersion = packageJson.version; | ||
this.agentVersion = '1.1.0'; | ||
// main thread name | ||
@@ -213,3 +211,5 @@ this.mainThread = 'main'; | ||
// retrieve calling module object | ||
_a = moduleResolver_1.readModule(this.stackTrace.getCallingModulePath()), this._callingModule = _a[0], this._callingModulePath = _a[1]; | ||
if (!this.attributes.hasOwnProperty('application')) { | ||
_a = moduleResolver_1.readModule(this.stackTrace.getCallingModulePath()), this._callingModule = _a[0], this._callingModulePath = _a[1]; | ||
} | ||
// combine attributes | ||
@@ -255,3 +255,2 @@ this.attributes = tslib_1.__assign(tslib_1.__assign({}, this.readBuiltInAttributes()), this.clientAttributes); | ||
var mem = process.memoryUsage(); | ||
var _a = (this._callingModule || {}), name = _a.name, version = _a.version, main = _a.main, description = _a.description, author = _a.author; | ||
var result = { | ||
@@ -268,11 +267,15 @@ 'process.age': Math.floor(process.uptime()), | ||
'debug.port': process.debugPort, | ||
application: name, | ||
version: version, | ||
main: main, | ||
description: description, | ||
author: author, | ||
guid: node_machine_id_1.machineIdSync(true), | ||
'backtrace.version': this.agentVersion, | ||
guid: BacktraceReport.machineId, | ||
hostname: os.hostname(), | ||
}; | ||
var cpus = os.cpus(); | ||
if (this._callingModule) { | ||
var _a = (this._callingModule || {}), name_1 = _a.name, version = _a.version, main = _a.main, description = _a.description, author = _a.author; | ||
result['name'] = name_1; | ||
result['version'] = version; | ||
result['main'] = main; | ||
result['description'] = description; | ||
result['author'] = typeof author === 'object' && author.name ? author.name : author; | ||
} | ||
if (cpus && cpus.length > 0) { | ||
@@ -288,3 +291,2 @@ result['cpu.count'] = cpus.length; | ||
'Exec Arguments': process.execArgv, | ||
Dependencies: moduleResolver_1.readModuleDependencies(this._callingModulePath), | ||
}; | ||
@@ -312,2 +314,3 @@ if (this.detectReportType(this.err)) { | ||
}; | ||
BacktraceReport.machineId = node_machine_id_1.machineIdSync(true); | ||
return BacktraceReport; | ||
@@ -314,0 +317,0 @@ }()); |
@@ -0,0 +0,0 @@ import { BacktraceReport } from './backtraceReport'; |
@@ -0,0 +0,0 @@ "use strict"; |
@@ -7,4 +7,4 @@ import { ISourceCode } from './sourceCode'; | ||
funcName: string; | ||
sourceCode: string; | ||
library: string; | ||
sourceCode: string | undefined; | ||
path: string; | ||
line: number; | ||
@@ -11,0 +11,0 @@ column: number; |
@@ -6,3 +6,3 @@ "use strict"; | ||
var fs = tslib_1.__importStar(require("fs")); | ||
var path_1 = require("path"); | ||
var path = tslib_1.__importStar(require("path")); | ||
var source_scan_1 = require("source-scan"); | ||
@@ -40,3 +40,13 @@ /** | ||
if (!this.callingModulePath) { | ||
this.callingModulePath = this.stack[0].sourceCode; | ||
var sourceCode = this.stack.find(function (n) { return !!n.sourceCode; }); | ||
if (!sourceCode) { | ||
return undefined; | ||
} | ||
for (var key in this.requestedSourceCode) { | ||
if (this.requestedSourceCode.hasOwnProperty(key)) { | ||
if (this.requestedSourceCode[key].id === sourceCode.sourceCode) { | ||
this.callingModulePath = key; | ||
} | ||
} | ||
} | ||
} | ||
@@ -66,3 +76,3 @@ return this.callingModulePath; | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var stackTrace, lines, backtracePath; | ||
var stackTrace, appPath, lines, backtracePath; | ||
var _this = this; | ||
@@ -76,4 +86,5 @@ return tslib_1.__generator(this, function (_a) { | ||
} | ||
appPath = process.cwd(); | ||
lines = stackTrace.split('\n').slice(1); | ||
backtracePath = path_1.join('node_modules', 'backtrace-node'); | ||
backtracePath = path.join('node_modules', 'backtrace-node'); | ||
lines.forEach(function (line) { | ||
@@ -84,10 +95,14 @@ var match = line.match(_this.stackLineRe); | ||
} | ||
var backtraceLibStackFrame = match[2].indexOf(backtracePath) !== -1; | ||
var fullSourceCodePath = match[2]; | ||
var backtraceLibStackFrame = fullSourceCodePath.indexOf(backtracePath) !== -1; | ||
if (backtraceLibStackFrame) { | ||
return; | ||
} | ||
var sourcePath = fullSourceCodePath; | ||
if (sourcePath) { | ||
sourcePath = path.relative(appPath, sourcePath); | ||
} | ||
var stackFrame = { | ||
funcName: match[1], | ||
sourceCode: match[2], | ||
library: match[2], | ||
path: sourcePath, | ||
line: parseInt(match[3], 10), | ||
@@ -97,12 +112,12 @@ column: parseInt(match[4], 10), | ||
// ignore not existing stack frames | ||
if (fs.existsSync(stackFrame.sourceCode)) { | ||
_this.addSourceRequest(stackFrame); | ||
if (fs.existsSync(fullSourceCodePath)) { | ||
stackFrame.sourceCode = _this.addSourceRequest(stackFrame, fullSourceCodePath); | ||
// extend root object with symbolication information | ||
if (includeSymbolication) { | ||
_this.symbolicationPaths.add(stackFrame.sourceCode); | ||
_this.symbolicationPaths.add(fullSourceCodePath); | ||
} | ||
if (_this.isCallingModule(fullSourceCodePath)) { | ||
_this.callingModulePath = fullSourceCodePath; | ||
} | ||
} | ||
if (_this.isCallingModule(stackFrame)) { | ||
_this.callingModulePath = stackFrame.sourceCode; | ||
} | ||
_this.stack.push(stackFrame); | ||
@@ -134,5 +149,3 @@ }); | ||
file = fs.readFileSync(symbolicationPath, 'utf8'); | ||
hash = crypto_1.createHash('md5') | ||
.update(file) | ||
.digest('hex'); | ||
hash = crypto_1.createHash('md5').update(file).digest('hex'); | ||
(_a = this.symbolicationMaps) === null || _a === void 0 ? void 0 : _a.push({ | ||
@@ -157,9 +170,15 @@ file: symbolicationPath, | ||
}; | ||
BacktraceStackTrace.prototype.addSourceRequest = function (stackFrame) { | ||
BacktraceStackTrace.prototype.addSourceRequest = function (stackFrame, fullPath) { | ||
// add source code to existing list. Otherwise create empty array | ||
this.requestedSourceCode[stackFrame.sourceCode] = this.requestedSourceCode[stackFrame.sourceCode] || []; | ||
this.requestedSourceCode[stackFrame.sourceCode].push({ | ||
if (!this.requestedSourceCode[fullPath]) { | ||
this.requestedSourceCode[fullPath] = { | ||
data: [], | ||
id: crypto_1.randomBytes(20).toString('hex'), | ||
}; | ||
} | ||
this.requestedSourceCode[fullPath].data.push({ | ||
line: stackFrame.line, | ||
column: stackFrame.column, | ||
}); | ||
return this.requestedSourceCode[fullPath].id; | ||
}; | ||
@@ -182,6 +201,6 @@ BacktraceStackTrace.prototype.readSourceCode = function () { | ||
element = this.requestedSourceCode[key]; | ||
minLine = element[0].line; | ||
minLine = element.data[0].line; | ||
maxLine = minLine; | ||
for (i = 1; i < element.length; i += 1) { | ||
item = element[i]; | ||
for (i = 1; i < element.data.length; i += 1) { | ||
item = element.data[i]; | ||
minLine = Math.min(minLine, item.line); | ||
@@ -198,3 +217,3 @@ maxLine = Math.max(maxLine, item.line); | ||
res = _c.sent(); | ||
this.sourceCodeInformation[key] = res; | ||
this.sourceCodeInformation[element.id] = res; | ||
_c.label = 3; | ||
@@ -220,3 +239,2 @@ case 3: | ||
res({ | ||
path: parameter.filePath, | ||
startLine: parameter.startLine + 1, | ||
@@ -232,4 +250,4 @@ startColumn: 1, | ||
}; | ||
BacktraceStackTrace.prototype.isCallingModule = function (stackFrame) { | ||
return (!this.callingModulePath && fs.existsSync(stackFrame.sourceCode) && !stackFrame.sourceCode.includes('node_modules')); | ||
BacktraceStackTrace.prototype.isCallingModule = function (sourcePath) { | ||
return !!sourcePath && !this.callingModulePath && !sourcePath.includes('node_modules'); | ||
}; | ||
@@ -236,0 +254,0 @@ return BacktraceStackTrace; |
export interface ISourceCode { | ||
path: string; | ||
startLine: number; | ||
@@ -4,0 +3,0 @@ startColumn: number; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
//# sourceMappingURL=sourceCode.js.map |
{ | ||
"name": "backtrace-node", | ||
"version": "1.0.9", | ||
"version": "1.1.0", | ||
"description": "Backtrace error reporting tool", | ||
@@ -46,7 +46,7 @@ "main": "./lib/index.js", | ||
"@types/mocha": "^5.2.6", | ||
"@types/nock": "^9.3.1", | ||
"@types/nock": "^11.1.0", | ||
"@types/node": "^11.11.4", | ||
"chai": "~4.2.0", | ||
"mocha": "^5.2.0", | ||
"nock": "^10.0.6", | ||
"mocha": "^8.4.0", | ||
"nock": "^13.1.0", | ||
"ts-node": "^8.0.3", | ||
@@ -53,0 +53,0 @@ "tslint-config-prettier": "^1.18.0", |
@@ -1,5 +0,6 @@ | ||
import { ClientRateLimit } from './clientRateLimit'; | ||
import { EventEmitter } from 'events'; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import { BacktraceApi } from './backtraceApi'; | ||
import { ClientRateLimit } from './clientRateLimit'; | ||
import { BacktraceClientOptions, IBacktraceClientOptions } from './model/backtraceClientOptions'; | ||
@@ -9,2 +10,3 @@ import { IBacktraceData } from './model/backtraceData'; | ||
import { BacktraceResult } from './model/backtraceResult'; | ||
/** | ||
@@ -15,2 +17,3 @@ * Backtrace client | ||
public options: BacktraceClientOptions; | ||
private _scopedAttributes: object = {}; | ||
private _memorizedAttributes: object = {}; | ||
@@ -34,2 +37,3 @@ private _backtraceApi: BacktraceApi; | ||
this.registerHandlers(); | ||
this.setupScopedAttributes(); | ||
} | ||
@@ -211,2 +215,3 @@ | ||
...this.getMemorizedAttributes(), | ||
...this._scopedAttributes, | ||
}; | ||
@@ -241,2 +246,16 @@ } | ||
} | ||
private setupScopedAttributes() { | ||
const applicationPackageJsonPath = path.join(process.cwd(), 'package.json'); | ||
if (!fs.existsSync(applicationPackageJsonPath)) { | ||
return; | ||
} | ||
const json = JSON.parse(fs.readFileSync(applicationPackageJsonPath, 'utf8')); | ||
this._scopedAttributes = { | ||
'application.version': json.version, | ||
application: json.name, | ||
main: json.main, | ||
description: json.description, | ||
author: typeof json.author === 'object' && json.author.name ? json.author.name : json.author, | ||
}; | ||
} | ||
@@ -243,0 +262,0 @@ private registerGlobalHandler(multipleExceptionListener: boolean): void { |
@@ -0,0 +0,0 @@ import { BacktraceClient } from './backtraceClient'; |
@@ -1,7 +0,5 @@ | ||
// tslint:disable-next-line: no-var-requires | ||
const packageJson = require('./../../package.json'); | ||
import { pseudoRandomBytes } from 'crypto'; | ||
import { machineIdSync } from 'node-machine-id'; | ||
import * as os from 'os'; | ||
import { readModule, readModuleDependencies } from '../helpers/moduleResolver'; | ||
import { readModule } from '../helpers/moduleResolver'; | ||
import { readMemoryInformation, readProcessStatus } from '../helpers/processHelper'; | ||
@@ -15,2 +13,4 @@ import { IBacktraceData } from './backtraceData'; | ||
export class BacktraceReport { | ||
private static machineId = machineIdSync(true); | ||
public set symbolication(symbolication: boolean) { | ||
@@ -44,5 +44,5 @@ this._symbolication = symbolication; | ||
// Backtrace-ndoe name | ||
public readonly agent = packageJson.name; | ||
public readonly agent = 'backtrace-node'; | ||
// Backtrace-node version | ||
public readonly agentVersion = packageJson.version; | ||
public readonly agentVersion = '1.1.0'; | ||
// main thread name | ||
@@ -239,3 +239,5 @@ public readonly mainThread = 'main'; | ||
// retrieve calling module object | ||
[this._callingModule, this._callingModulePath] = readModule(this.stackTrace.getCallingModulePath()); | ||
if (!this.attributes.hasOwnProperty('application')) { | ||
[this._callingModule, this._callingModulePath] = readModule(this.stackTrace.getCallingModulePath()); | ||
} | ||
@@ -293,3 +295,2 @@ // combine attributes | ||
const mem = process.memoryUsage(); | ||
const { name, version, main, description, author } = (this._callingModule || {}) as any; | ||
const result = { | ||
@@ -306,8 +307,4 @@ 'process.age': Math.floor(process.uptime()), | ||
'debug.port': process.debugPort, | ||
application: name, | ||
version, | ||
main, | ||
description, | ||
author, | ||
guid: machineIdSync(true), | ||
'backtrace.version': this.agentVersion, | ||
guid: BacktraceReport.machineId, | ||
hostname: os.hostname(), | ||
@@ -317,2 +314,10 @@ } as any; | ||
const cpus = os.cpus(); | ||
if (this._callingModule) { | ||
const { name, version, main, description, author } = (this._callingModule || {}) as any; | ||
result['name'] = name; | ||
result['version'] = version; | ||
result['main'] = main; | ||
result['description'] = description; | ||
result['author'] = typeof author === 'object' && author.name ? author.name : author; | ||
} | ||
@@ -330,3 +335,2 @@ if (cpus && cpus.length > 0) { | ||
'Exec Arguments': process.execArgv, | ||
Dependencies: readModuleDependencies(this._callingModulePath), | ||
} as any; | ||
@@ -333,0 +337,0 @@ |
@@ -1,6 +0,5 @@ | ||
import { createHash } from 'crypto'; | ||
import { createHash, randomBytes } from 'crypto'; | ||
import * as fs from 'fs'; | ||
import { join } from 'path'; | ||
import * as path from 'path'; | ||
import { scanFile } from 'source-scan'; | ||
import { promisify } from 'util'; | ||
import { ISourceCode, ISourceLocation, ISourceScan } from './sourceCode'; | ||
@@ -13,4 +12,4 @@ | ||
funcName: string; | ||
sourceCode: string; | ||
library: string; | ||
sourceCode: string | undefined; | ||
path: string; | ||
line: number; | ||
@@ -35,3 +34,3 @@ column: number; | ||
private readonly stackLineRe = /\s+at (.+) \((.+):(\d+):(\d+)\)/; | ||
private requestedSourceCode: { [index: string]: ISourceLocation[] } = {}; | ||
private requestedSourceCode: { [path: string]: { id: string; data: ISourceLocation[] } } = {}; | ||
@@ -57,3 +56,13 @@ private tabWidth: number = 8; | ||
if (!this.callingModulePath) { | ||
this.callingModulePath = this.stack[0].sourceCode; | ||
const sourceCode = this.stack.find((n) => !!n.sourceCode); | ||
if (!sourceCode) { | ||
return undefined; | ||
} | ||
for (const key in this.requestedSourceCode) { | ||
if (this.requestedSourceCode.hasOwnProperty(key)) { | ||
if (this.requestedSourceCode[key].id === sourceCode.sourceCode) { | ||
this.callingModulePath = key; | ||
} | ||
} | ||
} | ||
} | ||
@@ -89,5 +98,6 @@ return this.callingModulePath; | ||
} | ||
const appPath = process.cwd(); | ||
// get exception lines and remove first line of descrtiption | ||
const lines = stackTrace.split('\n').slice(1); | ||
const backtracePath = join('node_modules', 'backtrace-node'); | ||
const backtracePath = path.join('node_modules', 'backtrace-node'); | ||
lines.forEach((line) => { | ||
@@ -98,3 +108,4 @@ const match = line.match(this.stackLineRe); | ||
} | ||
const backtraceLibStackFrame = match[2].indexOf(backtracePath) !== -1; | ||
const fullSourceCodePath = match[2]; | ||
const backtraceLibStackFrame = fullSourceCodePath.indexOf(backtracePath) !== -1; | ||
if (backtraceLibStackFrame) { | ||
@@ -104,22 +115,26 @@ return; | ||
let sourcePath = fullSourceCodePath; | ||
if (sourcePath) { | ||
sourcePath = path.relative(appPath, sourcePath); | ||
} | ||
const stackFrame = { | ||
funcName: match[1], | ||
sourceCode: match[2], | ||
library: match[2], | ||
path: sourcePath, | ||
line: parseInt(match[3], 10), | ||
column: parseInt(match[4], 10), | ||
}; | ||
} as IBacktraceStackFrame; | ||
// ignore not existing stack frames | ||
if (fs.existsSync(stackFrame.sourceCode)) { | ||
this.addSourceRequest(stackFrame); | ||
if (fs.existsSync(fullSourceCodePath)) { | ||
stackFrame.sourceCode = this.addSourceRequest(stackFrame, fullSourceCodePath); | ||
// extend root object with symbolication information | ||
if (includeSymbolication) { | ||
this.symbolicationPaths.add(stackFrame.sourceCode); | ||
this.symbolicationPaths.add(fullSourceCodePath); | ||
} | ||
if (this.isCallingModule(fullSourceCodePath)) { | ||
this.callingModulePath = fullSourceCodePath; | ||
} | ||
} | ||
if (this.isCallingModule(stackFrame)) { | ||
this.callingModulePath = stackFrame.sourceCode; | ||
} | ||
this.stack.push(stackFrame); | ||
@@ -141,5 +156,3 @@ }); | ||
const file = fs.readFileSync(symbolicationPath, 'utf8'); | ||
const hash = createHash('md5') | ||
.update(file) | ||
.digest('hex'); | ||
const hash = createHash('md5').update(file).digest('hex'); | ||
@@ -167,9 +180,15 @@ this.symbolicationMaps?.push({ | ||
private addSourceRequest(stackFrame: IBacktraceStackFrame): void { | ||
private addSourceRequest(stackFrame: IBacktraceStackFrame, fullPath: string): string { | ||
// add source code to existing list. Otherwise create empty array | ||
this.requestedSourceCode[stackFrame.sourceCode] = this.requestedSourceCode[stackFrame.sourceCode] || []; | ||
this.requestedSourceCode[stackFrame.sourceCode].push({ | ||
if (!this.requestedSourceCode[fullPath]) { | ||
this.requestedSourceCode[fullPath] = { | ||
data: [], | ||
id: randomBytes(20).toString('hex'), | ||
}; | ||
} | ||
this.requestedSourceCode[fullPath].data.push({ | ||
line: stackFrame.line, | ||
column: stackFrame.column, | ||
}); | ||
return this.requestedSourceCode[fullPath].id; | ||
} | ||
@@ -182,6 +201,6 @@ | ||
let minLine = element[0].line; | ||
let minLine = element.data[0].line; | ||
let maxLine = minLine; | ||
for (let i = 1; i < element.length; i += 1) { | ||
const item = element[i]; | ||
for (let i = 1; i < element.data.length; i += 1) { | ||
const item = element.data[i]; | ||
minLine = Math.min(minLine, item.line); | ||
@@ -197,3 +216,3 @@ maxLine = Math.max(maxLine, item.line); | ||
const res = await this.getSourceCodeInformation(parameter); | ||
this.sourceCodeInformation[key] = res; | ||
this.sourceCodeInformation[element.id] = res; | ||
} | ||
@@ -211,3 +230,2 @@ } | ||
res({ | ||
path: parameter.filePath, | ||
startLine: parameter.startLine + 1, | ||
@@ -222,7 +240,5 @@ startColumn: 1, | ||
private isCallingModule(stackFrame: IBacktraceStackFrame): boolean { | ||
return ( | ||
!this.callingModulePath && fs.existsSync(stackFrame.sourceCode) && !stackFrame.sourceCode.includes('node_modules') | ||
); | ||
private isCallingModule(sourcePath: string): boolean { | ||
return !!sourcePath && !this.callingModulePath && !sourcePath.includes('node_modules'); | ||
} | ||
} |
export interface ISourceCode { | ||
path: string; | ||
startLine: number; | ||
@@ -4,0 +3,0 @@ startColumn: number; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
174243
3347
9