microsoft/ptvsd

Stderr not showing up in Debug Console

haniamr opened this issue · 4 comments

Environment data

  • PTVSD version: 4.3.2 (also tried latest stable for debugpy)
  • OS and version: Host is Windows 10 and an Ubuntu container
  • Python version (& distribution if applicable, e.g. Anaconda): 3.8
  • Using VS Code or Visual Studio: VS Code

Actual behavior

Run a django app using a non-root user and attempt to bind to a port < 1024. This is expected to show this error: Error: You don't have permission to access that port.

The error does not show up in the Debug Console, although it shows up in the container logs. Here's what I see in the Debug Console:

Performing system checks...
System check identified no issues (0 silenced).
April 10, 2020 - 00:24:02
Django version 3.0.3, using settings 'web_project.settings'
Starting development server at http://0.0.0.0:1000/
Quit the server with CONTROL-C.

Expected behavior

The error should show up in the debug console.

Steps to reproduce:

  1. Clone this project: https://github.com/microsoft/python-sample-vscode-django-tutorial.git
  2. Switch to the branch "tutorial"
  3. Add Docker files to workspace (Docker extension has to be installed), choose Python: Django and choose port value 80
  4. Modify the Docker file by adding these lines before the CMD instruction:
RUN useradd appuser && chown -R appuser /app
USER appuser
  1. F5

Could that be happening due to the way Django kills the process when that error is thrown? https://github.com/django/django/blob/e3d0b4d5501c6d0bc39f035e4345e5bdfde12e41/django/core/management/commands/runserver.py#L154

That seems likely. Pydevd detours sys.stderr and streams it back as "output" events, but it's asynchronous. On a clean shutdown path, it can sync at the end (even if it's an error exit due to an exception etc). But if the process force-kills itself immediately after writing, it doesn't get any chance to do that.

This should work properly with "launch", because in that case we use a separate launcher process to spawn the debuggee, and the launcher also takes care of redirecting stdout/err. But for "attach", we don't control the spawning, and thus can only redirect the output from inside the process.

Thanks Pavel, is launching an option that the Docker extension can utilize? I thought that we had to do an attach since we’re running the process remotely...

It's not an option at the moment, but it would be feasible. In the launch scenario, there are four processes involved, with data flow like this:

IDE  <-> adapter <-> launcher
                 <-> debuggee

These are all on the same machine, but they all communicate with sockets anyway, except for IDE <-> adapter. In the attach scenario, you have:

IDE  <-> adapter <-> debuggee

and the network boundary depends on whether you use "connect" or "listen" - in particular, for "connect", it's between the IDE and the adapter, so it's also a socket.

Now, the adapter can handle either "launch" or "attach" requests, regardless of whether the client is talking to it over the pipe or over the socket. Other components artificially constrain it - specifically, the IDE will always spawn it locally and use pipes for launch or attach+listen; and the debuggee will spawn it remotely and tell it to use sockets for attach+connect.

However, we could allow "connect" in conjunction with "launch". You could then manually launch the adapter specifically on remote machine, connect VSCode to it using a socket, and have it process a "launch" request. The only catch that I can see is that it would only work with "console": "internalConsole", because otherwise the remote adapter will try to spawn launcher inside VSCode terminal on the local machine.

This would require us to maintain a standard CLI for the adapter, however. Right now, the only thing that we guarantee is that if you run it without any switches, it'll talk DAP over stdin/out - all switches for using sockets etc are considered internal.

Thanks for the detailed explanation, Pavel! I'll close this issue for now and setup a meeting to chat more about the "launch" scenario.