extended node debugger
tracing bugs, variables, understanding large web app flows are difficult, imagine stepping through 100k lines of your own company's large project codebase with many internal framework and librarys' codebase, it is a nightmare, with ndx debugger, you can easily step through the the kinds of source code you want and watch any incoming arguments, and you can also create custom watchers to automate this process, what a hack!!!
- able to register watchers to automate the debugging process
Watcher#onDebugEvent
interface returns inspector object based on v8 debugger protocol- watcher enables to blackbox and stepover the custom or internal scripts when stepping and trace function calls and variables
- separated server executable and client cli makes debugging dockerized node app possible
- support automatically print out all function calls with arguments and catching errors with configurable included files
- add typings to watchers
- support debugging typescript application with source map support
- update the cli interface for readability
- support Nestjs framework debugging by providing NestJs Watchers
yarn global add @ecpy/ndx
# help
npx @ecpy/ndx --help
# launch debug server
npx @ecpy/ndx -s -h localhost -p 3000 $APP
# launch as debug cli client with watchers
npx @ecpy/ndx -c -h localhost -p 3000 -w $WATCHERS_FILE
- watcher samples are located at ${PACKAGE_ROOT}/watcher-samples
cd $PACKAGE_ROOT
# test server
./cli.js -s -h localhost -p 3000 ./app-sample
# test client
./cli.js -c -h localhost -p 3000 -w ./watcher-samples/index.js
ndx> pause
ndx> next
# debug APIs
ndx> help
- watcher class structure
import * as helpers from './helpers';
import { Watcher, Inspector, InspectorEventParam, InspectorDomain } from '../lib/watcher-service';
export default class InternalScriptWatcher extends Watcher {
private internalScriptIds: number[]
private isProcessing: boolean
constructor() {
super();
this.internalScriptIds = [];
}
onDebugEvent(inspector: Inspector, domain: InspectorDomain, name: string, param: InspectorEventParam, nextWatcher: Function) {
if (domain == 'Debugger') {
if (['scriptParsed'].includes(name)) {
if (!param.url.startsWith('file://')) this.internalScriptIds.push(param.scriptId);
return;
}
if (['paused'].includes(name)) {
inspector.enablePrint(false);
const scriptId = helpers.getPausedScriptId(param);
if (this.internalScriptIds.includes(scriptId)) {
inspector.Debugger.stepInto();
inspector.enableInput(false);
if (!this.isProcessing) this.log('start processing...');
this.isProcessing = true;
} else {
inspector.enablePrint(true);
inspector.enableInput(true);
if (this.isProcessing) this.log('processed.');
this.isProcessing = false;
}
return;
}
}
if (!this.isProcessing) nextWatcher();
}
}
- protocol method calls are defined on the inspector object returned by
Watcher#onDebugEvent
interface, see v8 debugger protocol
- parts of the debugger structure is referenced from node-inspect