xdebug / vscode-php-debug

PHP Debug Adapter for Visual Studio Code 🐞⛔
MIT License
768 stars 175 forks source link

How do I get "PHP Debug" to listen for api calls #899

Closed homer-reynolds closed 11 months ago

homer-reynolds commented 1 year ago

How I set this up to get the debugger to listen for my api calls?

PHP version: 8.1.13 Xdebug version: v3.2.0 VS Code extension version: v1.32.1

Your launch.json:

{ // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [

    {
        "name": "Attach to Chrome",
        "port": 9222,
        "request": "attach",
        "type": "chrome",
        "webRoot": "${workspaceFolder}"
    },
    {
        "name": "Listen for Xdebug",
        "type": "php",
        "request": "launch",
        "port": 9003
    },
    {
        "name": "Launch currently open script",
        "type": "php",
        "request": "launch",
        "program": "${file}",
        "cwd": "${fileDirname}",
        "port": 0,
        "runtimeArgs": [
            "-dxdebug.start_with_request=yes"
        ],
        "env": {
            "XDEBUG_MODE": "debug,develop",
            "XDEBUG_CONFIG": "client_port=${port}"
        }
    },
    {
        "name": "Launch Built-in web server",
        "type": "php",
        "request": "launch",
        "runtimeArgs": [
            "-dxdebug.mode=debug",
            "-dxdebug.start_with_request=yes",
            "-S",
            "localhost:0"
        ],
        "program": "",
        "cwd": "${workspaceRoot}",
        "port": 9003,
        "serverReadyAction": {
            "pattern": "Development Server \\(http://localhost:([0-9]+)\\) started",
            "uriFormat": "http://localhost:%s",
            "action": "openExternally"
        }
    }
]

}

Xdebug php.ini config:

[PHP] post_max_size = 100M upload_max_filesize = 100M variables_order = EGPCS

xdebug.mode = debug xdebug.start_with_request = yes

Xdebug logfile (from setting xdebug.log in php.ini):

There is no logfile setup in the php.ini.

VS Code extension logfile (from setting "log": true in launch.json):

I do not know how to set this up.

Code snippet to reproduce:

zobo commented 1 year ago

Hi. I cannot make out much what you are trying to do.

Are you able to debug a simple PHP script or page?

Best starting point is to create a test.php file that you can open in your browser and than add


xdebug_info();
xdebug_break();
echo "TEST";

and load it in the browser. There should be enough debug data there to get you started.

josja commented 11 months ago

I have the same issue. My PHP webservice is running in a Docker container with XDebug enabled on port 9001, I use Postman to validate the API calls.

Starting the default configured xdebug session in VS Code launches a new PHP server and sets up a XDebug session on port 9000. So my guess is no break points are hit because it spawned another process which is not being targeted by Postman.

I would expect an "attach" request instead of a "launch" could remedy this, but this is not supported by the type "PHP".

The webservice is a Symfony bundle so it is not that trivial to spawn it outside the container because of its dependence on vendor packages that were built inside the container (using composer.phar).

zobo commented 11 months ago

Hi! Xdebug works a bit different than the usual VM (V8, Java...) debuggers where the PHP process (with Xdebug extension loaded) TCP connects back to the IDE. This is why "attach" was never implemented as it makes no sense.

The "launch" option opens a TCP listen socket on specified port (9003 by default) and can also optionally start a PHP process - either a CLI script, or the PHP dev server (php -S). The IDE then waits for Xdebug to connect to it. What the IDE cannot do is start a web server like nginx or docker... (well, technically it could, but this is left for the very creative users) - it also would not make much sense.

So in your case, where your PHP process is running inside Docker, you need to tell Xdebug to connect to the HOST IP on the port the IDE is listening and/or tell the IDE to listen on the correct port.

First make a script that contains xdebug_info(); that should print all the relevant Xdebug configuration. Then make needed adjustments to Xdebug either via .ini files or XDEBUG_CONFIG.

Also look at host.docker.internal or gateway.docker.internal as helpers.

Then you need to trigger debugging. Either by setting start_with_request in .ini file or by making a request with the XDEBUG_SESSION cookie.

All this should also be evident in the log printed by xdebug_info();

One last thing you need is to provide path mappings in launch.json because your PHP inside the container will most likely see files in different locations than your IDE outside the container.

Let me know how it goes. As the OP did not provide additional info, I intend to close this issue.

Also, Derick made a lot of videos explaining variolous setups. Here is - although a bit older - video talking about VS Code and Docker. https://www.youtube.com/watch?v=ZIGdBSD6zvU&t=197s

josja commented 11 months ago

Thank you Zobo, I now see the mistake in my thinking and got a bit further in my setup. Still my breakpoints are not being hit, years ago I managed to get XDebug working fine with PHP Storm but now a bit stuck with the VS Code config. I agree it should not attach indeed

zobo commented 11 months ago

Have you tried what I suggested with xdebug_info();? Also try adding xdebug_break(); somewhere in the code path. It triggers a breakpoint. Maybe that will give you some additional hints.

zobo commented 11 months ago

If you post a screenshot of xdebug_info log and modes I can maybe see what the issue is.

josja commented 11 months ago

Here is the screenshot of xdebug_info()

xdebuginfo

josja commented 11 months ago

Thank you Zobo, for your time and effort. My verified working setup did not depend on any IDEKEY so I deleted the idekey. One might think 'localhost' as client host would be good enough but it isn't, it was the CLIENT_HOST that needed to be set to the docker internal host IP.

Current PHP 8.2 dockerfile with the Xdebug config, setting correct client host and port:

# install xdebug
RUN pecl install xdebug
RUN docker-php-ext-enable xdebug
RUN echo "error_reporting = E_ALL" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_startup_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "display_errors = On" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.mode=debug" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.discover_client_host=1" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.client_port=9001" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
RUN echo "xdebug.client_host=host.docker.internal" >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini

Your docker-compose file should NOT expose (and hijack) port 9001 (my first mistake, thanks Zobo):

services:
    php:
        build:
            context: php82-fpm
            args:
                TIMEZONE: ${TIMEZONE}
        ports:
            - 9001:9001 <=============================== WRONG, DELETE ! ==========
        volumes:
            - ${SYMFONY_APP_PATH}:/var/www/symfony

Current VSCode launch.json with working path mapping, should have matching port 9001:

"configurations": [
    {
        "name": "Listen for Xdebug",
        "type": "php",
        "request": "launch",
        "port": 9001,
        "pathMappings": {
            "/var/www": "${workspaceRoot}/"
          }
    },

And one more IMPORTANT thing to remember when you are using anything other than a webbrowser you need to start the debug session in your API client. In my case I test my API with Postman, so you must add a XDEBUG_SESSION_START parameter (with your IDEKEY as value, but empty value if you did not set the IDEKEY, like me) to every API request you want to debug (you can add this parameter by default with Postman):

Screenshot 2023-08-22 at 22 24 02
zobo commented 11 months ago

Thanks so much for the feedback, let me give you just a few comments here.

  1. Correct, the IDEKEY is irrelevant as it is not used for filtering connections (nor are you using dbgpproxy here).
  2. client_host is relevant as the IDE and PHP are on different networks (docker in this case). You can use either the Docker provided host.docker.internal, a specific IP or maybe even one of the new Xdebug magic pseudo-hosts xdebug://gateway or xdebug://nameserver.
  3. I suggest you use port 9003 as it is the default port and thus does not need to be explicitly set in either php.ini nor launch.json.
  4. If you explicitly set xdebug.client_host enabling xdebug.discover_client_host doesn't make much sense - it does have precedence though. See https://xdebug.org/docs/all_settings#discover_client_host. I'd suggest removing it.
  5. Since you are not adjusting any other Xdebug specific php.ini settings you could also just use the these two ENV variables in your docker-compose:
    environment:
    - XDEBUG_MODE=debug
    - XDEBUG_CONFIG=client_host=host.docker.internal
  6. You are correct about XDEBUG_SESSION_START, however, if you can also use the cookie XDEBUG_SESSION=vsc or jus set xdebug.start_with_request

With Xdebug today, a lot of things just work out of the box. You just need to enable debugging (XDEBUG_MODE=debug). If you are using Docker the main thing is to let Xdebug know how to connect to the IDE (client_host).

Hope you get much value out of using this extension, and if you see any room for improvements open an issue and I'll see what I can do.