Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use source maps if extension ships one for error stack trace formatting #145473

Open
davidanthoff opened this issue Mar 20, 2022 · 3 comments · May be fixed by #238469 or microsoft/vscode-js-debug#2160
Open
Labels
extension-host Extension host issues feature-request Request for new features or functionality
Milestone

Comments

@davidanthoff
Copy link
Contributor

In the Julia extension we have crash reporting setup, so that we send a crash report whenever an exception occurs in our extension. We also bundle our extension with webpack. One problem is that the stack traces in the exceptions (if something goes wrong) are essentially useless, as they refer to locations in the bundled version of the extension, i.e. everything on line 1 :) We do actually ship a source map file in the extension, but the information in there doesn't show up in the exception objects.

I think there are broadly speaking two ways to improve the situation: 1) run the extension host with the --enable-source-maps flag (but note that any custom Error.prepareStackTrace handler is then disabled, or 2) modify the already existing Error.prepareStackTrace handler in the extension host

(<any>Error).prepareStackTrace = (error: Error, stackTrace: errors.V8CallSite[]) => {
to apply source map information if it is there.

I am experimenting with that at the moment by using the https://www.npmjs.com/package/source-map-support package in our extension. That actually does lead to error objects that have stack traces that use the source map information, so that is great. The drawback, though, is that by using this package I think we are overriding the default VS Code Error.prepareStackTrace handler that gets set here, and potentially even for not just our extension? That seems really bad, but at the moment I don't really have a better idea on how to handle that...

I think the ideal situation is that the default Error.prepareStackTrace that the VS Code extension hosts installs essentially provides the same functionality that the source-map-support package provides.

@weinand weinand assigned jrieken and unassigned weinand Mar 20, 2022
@jrieken jrieken added this to the Backlog Candidates milestone Mar 21, 2022
@jrieken jrieken added feature-request Request for new features or functionality extension-host Extension host issues labels Mar 21, 2022
@jrieken jrieken removed their assignment Mar 21, 2022
@James4Ever0
Copy link

James4Ever0 commented Jan 15, 2025

A little help here: fullstack-build/tslog#205 (comment)

source-map-support is useful. It makes tslog able to track down to the source.

By the way how to add that argument --enable-source-maps to the extension host? Editing args in the file .vscode/launch.json does not help with tslog.


According to the official documentation, I think the executable code is actually electron, so I should use --js-flags="--enable-source-maps" instead. But it is not working.

electron/electron#38875


This issue says the extension host is running as Node.js but how to configure its command line? If via NODE_OPTIONS but how?

microsoft/vscode-discussions#1347

microsoft/vscode-js-debug#2010

#78460


Code for wrapping extension host console methods:

    this._wrapConsoleMethod('info', 'log');
    this._wrapConsoleMethod('log', 'log');
    this._wrapConsoleMethod('warn', 'warn');
    this._wrapConsoleMethod('debug', 'debug');
    this._wrapConsoleMethod('error', 'error');

Code for running extension process:

    const serviceName = `${this.configuration.type}-${this.id}`;
    const modulePath = FileAccess.asFileUri('bootstrap-fork.js').fsPath;
    const args = this.configuration.args ?? [];
    const execArgv = this.configuration.execArgv ?? [];
    const allowLoadingUnsignedLibraries = this.configuration.allowLoadingUnsignedLibraries;
    const respondToAuthRequestsFromMainProcess = this.configuration.respondToAuthRequestsFromMainProcess;
    const stdio = 'pipe';
    const env = this.createEnv(configuration);

    this.log('creating new...', Severity.Info);

    // Fork utility process
    this.process = utilityProcess.fork(modulePath, args, {
         serviceName,
         env,
         execArgv,
         allowLoadingUnsignedLibraries,
         respondToAuthRequestsFromMainProcess,
         stdio
    });

According to this article, a faulty debugger seems to be blamed. You could try the Chrome Javascript debugger for Node.js, and the source map support is added automatically. To resolve the incorrect console.log line number display problem, one could exclude the entire VSCode installation directory from source files in the debugger. I believe these settings should be possible in the VSCode extension debugger.

Also if the official Electron build does not comply with the need of most VSCode users, Microsoft could build a custom version of Electron with more Node.js command line flags, or just discard every such restriction for convenience.


I think I have found where to specify the NODE_OPTIONS or more command line flags. First you would search inspect-brk-extensions in both vscode and vscode-js-debug, then you could find code for Node.js extension setup, launching extensionHost and so on.


After a few trials, I can confirm that setting .vscode/launch.json > configurations[] > env > NODE_OPTIONS is sufficient for passing --enable-source-maps to the extension process, as long as the flag is permitted in Electron.

One can verify if it is working by calling console.trace() in the extension.


Even though I have patched the original Electron binary and got more NODE_OPTIONS, it seems the VSCode extension host has changed Error.prepareStackTrace so that it is not effective to get the source-mapped source line in the stack trace when an error has been raised, or my patch is to be blamed.

Before patching:

before.png

After patching:

after.png

@James4Ever0
Copy link

James4Ever0 commented Jan 21, 2025

I think there are broadly speaking two ways to improve the situation: 1) run the extension host with the --enable-source-maps flag (but note that any custom Error.prepareStackTrace handler is then disabled, or 2) modify the already existing Error.prepareStackTrace handler in the extension host to apply source map information if it is there.

Now it is called prepareStackTraceAndFindExtension.

After compilation, two files will contain the same parts modifying Error.prepareStackTrace, which are:

  • ${execInstallFolder}/resources/app/out/vs/workbench/api/node/extensionHostProcess.js
  • ${execInstallFolder}/resources/app/out/vs/workbench/api/worker/extensionHostWorkerMain.js (ineffective if changed)

By restoring original Error.prepareStackTrace and using the modified Electron.exe, I have finally had good news. It did use the source map to show the stack trace, though extremely slow. Is it because of the online source maps in VSCode scripts?

In this case, we could have three optuons:

  • Make a faster --enable-source-maps implementation
  • Modify prepareStackTraceAndFindExtension to get the source line from source maps
  • Conditionally run sourceMapSupport.install() in resources/app/out/bootstrap-fork.js

I have a hackish solution that could solve the problem once and for all. This requires source-map-support added to package.json > dependencies. Simply obtain the extension workspace folder through a environment variable VSCODE_EXTENSION_DEVELOPMENT_PATH in .vscode/launch.json, and patch the overridden Module._load method in src/vs/workbench/api/node/extensionHostProcess.ts. You will import and install source-map-support just before importing the extension for debugging, so you would filter it by the first argument of this method and install source-map-support for exactly once.

According to the source code above, Error.prepareStackTrace would not be overwritten but merged, because source-map-support does not use Object.defineProperty but the setter method for installation.

@James4Ever0
Copy link

@roblourens

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
extension-host Extension host issues feature-request Request for new features or functionality
Projects
None yet
5 participants
@davidanthoff @jrieken @weinand @James4Ever0 and others