Tuesday, December 2, 2008

Remote CLI Debugging via Eclipse PDT

About a month ago, I finally sat still long enough to get "PHP Web Page" debugging via Xdebug figured out in Eclipse PDT. As far as my Eclipse setup went, this involved installing PHP itself locally with xdebug added, and telling Eclipse where I put it all. From the very first remote PHP file I ran through the debug session, I could tell I've been missing out on a very useful tool. The only complaint I had with it was that Eclipse doesn't list the tracked variables in any rational order, meaning I have to hunt for each and every one I want to view. Hover-over-the-code popups For The Save, I suppose...

This week, I found a need to do this same kind of remote debugging, but for a command-line PHP script. This seems to be something that Eclipse is not already designed to do, as there is no "perpetual listener" available for its debug client. Instructions for remote CLI debugging are available, which showed me that environment variables might be the missing link to getting it working with Eclipse. It turned out to be one of two missing links. The other link was tricking Eclipse into keeping a debug session open (and therefore "listening").

I won't go into the the php.ini settings for xdebug that must be configured for remote debugging, since they're well documented for remote "PHP Web Page" debugging in Eclipse. Performing the remote CLI debugging did not require anything additional on that front.

The xdebug manual shows that the XDEBUG_CONFIG environment variable should contain the xdebug "idekey" setting in it, e.g. export XDEBUG_CONFIG="idekey=session_name". What confused me early on was that this setting was already visible in phpinfo() output, and was set to my shell username. Only later did I discover that it needed to match the XDEBUG_SESSION_START value that Eclipse itself was passing. I believe this value is configurable in Eclipse, though I've not looked it up yet. Given its default value of "ECLIPSE_DGBP", I'd say you might need to personalize it if you need multiple developers all trying to use Eclipse for remote debugging to the same remote server.

Another oddity that I didn't expect was needing to export that same XDEBUG_SESSION_START variable in the remote shell. The last item I had to add to put it all together was including "-f" in the PHP command syntax... just using "php foo.php" wouldn't work, but "php -f foo.php" did.

So, the final syntax to use when starting the PHP script in the remote CLI is:

XDEBUG_CONFIG="idekey=ECLIPSE_DBGP" \
XDEBUG_SESSION_START=ECLIPSE_DBGP \
php -f foo.php


This launches the PHP process with the environment it needs to contact your Eclipse instance... well, again, assuming you'd already configured the php.ini settings for xdebug to allow Eclipse's regular "PHP Web Page" debugging to work with this remote server.

In order for Eclipse to be listening for that debug session coming from the remote CLI script, I had to ahead of time launch a regular "PHP Web Page" debug session for some apache-available PHP file on the remote server, step through to its end, and leave the debug session running. You'll know you've reached this condition if the execution stack showing in Eclipse shows "Remote Launch" instead of a filename on its innermost level, and highlighting this "Remote Launch" will then show you the red STOP button (which means the debug session is still running). One weird thing I've found is that Eclipse forces me to step through the file twice to reach this point. I've created a codeless PHP file to use as a basic launch point for my remote CLI debug sessions, containing nothing but comments reminding me of all this info.

Once you have your Eclipse debug session listening, you execute the remote CLI script at its command shell, and the debugging begins. I have Eclipse already configured to always break on the first line of each file, so that's where the CLI script first breaks. I see it "stuck" in the command shell, and I see all the PHP objects appear in the "Variables" folder in the debug session.

I never found enough info online to get all these planets aligned just right, so I hope this post with it all spelled out proves helpful. After experimenting for several hours with adding more xdebug settings from php.ini into the XDEBUG_CONFIG variable, it was only on an odd whim that I tried setting the idekey to match that XDEBUG_SESSION_START value, and suddenly it worked. After that, I weeded out all the extra fluff I'd been including during my experiments, to finally end up with the syntax above as the minimal command needed.

11 comments:

Unknown said...

Yeah, I went through this exact same thing using Komodo.

I ended up just creating 2 aliases in my shell:

xdebug-off='unset XDEBUG_CONFIG'
xdebug-on='export XDEBUG_CONFIG="idekey="'

So I can easily toggle debug mode off/on before I run my CLI script.

Nice post.

Alan

The Nazg said...

@Alan,

Komodo was one of the few hits I got searching for "remote CLI debugging". It sounded like Komodo does have a "persistent listener" for its debugger, so that once you have it listening, you only have to concern yourself with the environment settings on your remote CLI side.

Nice aliases... those look like good shortcuts. For me so far, just having the Eclipse debug session still listening or not is enough of an "on/off" switch.

As an aside, I almost mentioned adding those settings to .profile or .bash_rc, to avoid needing to always specify them with every execution of the PHP script.

The Nazg said...

UPDATES:

While using the Eclipse debugger's step-through mechanisms, in some instances I'm seeing that the line that is highlighted in the code as the "next line to be executed" is actually one or two lines ahead of what it is actually about to execute. It's easy to enough to adjust your thinking for this, as long as you're aware that it's happening.

Another semi-related gotcha that I stumbled into yesterday, specific to using the Eclipse debugger with regular remote PHP web page debugging, is that when a page opens a new window, the execution of that new window is out of the debugger's scope. In order to keep debugging the code I was looking at, I had to temporarily modify it to run in the current window rather than opening up a new window.

Thought I'd pass those tidbits along...

Unknown said...

@Nazg

Oh interesting; yeah Komodo does leave open a persistent debug connection listener. That does make things a bit easier.

till said...

Just wanted to add -- great post!

The Nazg said...

UPDATE:

I found a "Use Multisession" option (Preferences -> PHP -> Debug -> Installed Debuggers -> Xdebug -> Configure) which makes the debugger continue debugging into a new window being opened.

The Nazg said...

UPDATE:

I had opened two requests with the PDT project to help with remote CLI debugging (258172 and 258175), and both have been included in the just released PDT 2.0. My thanks to Dave Kelsey for his efforts on these.

The Nazg said...

I *finally* made the time to find the new "remote session initiation" option in PDT 2.0, and it does indeed work for remote CLI debugging.

All you have to do, beyond the xdebug settings in the remote php.ini of course, is edit the "Accept remote session (JIT)" option in the Xdebug->Configure window of the PHP->Debug->Installed Debuggers preferences screen. You still need to have those environment variables set on your remote CLI.

When you run your remote CLI script, Eclipse will see the incoming connection and either "prompt" you to allow it, or automatically start the debug session (if set to "any"). In action, I see that it even leaves the debug listener running after your remote script finishes, thereby avoiding you having to confirm the incoming connection (if set to "prompt").

/me does his Happy Dance

Thanks again, Dave Kelsey for this welcome addition to PDT!

The Nazg said...

NOTE TO SELF:

XDEBUG_CONFIG="idekey=ECLIPSE_DBGP" \
XDEBUG_SESSION_START=ECLIPSE_DBGP \
php \
-d xdebug.remote_enable=on \
-d xdebug.remote_host={my IP} \
-f foo.php

Anonymous said...
This comment has been removed by the author.
Anonymous said...

This was a great help. THANKS!

(wouldn't let me edit, so had to delete and repost this)

If you find yourself with firewalls preventing the server from connecting to your Eclipse workstation via port 9000, you can use an SSH reverse tunnel to get past this.

ssh -R 9000:localhost:9000 {ssh UserId}@{remote server IP}

run this ssh command from your local workstation and then you can use the same debug command in 'The Nazg' June 23rd comment - but replace {my IP} with localhost.