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

Debugger: Windows compatibility #894

Merged
merged 8 commits into from
Feb 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,8 @@
"google-cloud": "dev/google-cloud"
},
"bin": [
"src/Core/bin/google-cloud-batch"
"src/Core/bin/google-cloud-batch",
"src/Debugger/bin/google-cloud-debugger"
],
"extra": {
"component": {
Expand Down
18 changes: 14 additions & 4 deletions src/Debugger/Agent.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

namespace Google\Cloud\Debugger;

use Google\Cloud\Core\Batch\BatchDaemonTrait;
use Google\Cloud\Core\Batch\BatchRunner;
use Google\Cloud\Core\Batch\BatchTrait;
use Google\Cloud\Core\ExponentialBackoff;
Expand All @@ -43,6 +44,7 @@
class Agent
{
use BatchTrait;
use BatchDaemonTrait;
use SysvTrait;

/**
Expand Down Expand Up @@ -99,10 +101,13 @@ public function __construct(array $options = [])
? $options['sourceRoot']
: dirname(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 1)[0]['file']);

$daemon = new Daemon([
'sourceRoot' => $this->sourceRoot,
'storage' => $storage
]);
if ($this->shouldStartDaemon()) {
$daemon = new Daemon([
'sourceRoot' => $this->sourceRoot,
'storage' => $storage,
'register' => true
]);
}

list($this->debuggeeId, $breakpoints) = $storage->load();

Expand Down Expand Up @@ -252,4 +257,9 @@ private function invalidateOpcache($breakpoint)

return opcache_invalidate($this->sourceRoot . DIRECTORY_SEPARATOR . $breakpoint->location()->path(), true);
}

private function shouldStartDaemon()
{
return $this->isDaemonRunning() && $this->isSysvIPCLoaded();
}
}
96 changes: 96 additions & 0 deletions src/Debugger/CliDaemon.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php
/**
* Copyright 2018 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Cloud\Debugger;

use Google\Cloud\Core\Batch\BatchDaemonTrait;
use Google\Cloud\Core\SysvTrait;

/**
* This class handles command line options and starts a configured Debugger
* Daemon.
*/
class CliDaemon
{
use BatchDaemonTrait;
use SysvTrait;

/**
* @var Daemon
*/
private $daemon;

/**
* Create a new DaemonCli instances.
*
* @param array $options [optional] {
* Configuration options.
*
* @type string $config Path to a configuration file that should return
* a Daemon instance.
* @type string $sourceRoot Path to the source root. Ignored if $config
* is set.
* }
*/
public function __construct(array $options = [])
{
$options += [
'config' => null,
'sourceRoot' => null
];
$config = $options['config'];
$sourceRoot = $options['sourceRoot'];

if ($config) {
if (!file_exists($config)) {
throw new \UnexpectedValueException("Config file '$config' does not exist.");
}
// Load the config file. The config file should return a configured
// Daemon instance.
$this->daemon = require_once $config;

if (!is_object($this->daemon) || get_class($this->daemon) !== Daemon::class) {
throw new \UnexpectedValueException('Config file does not return a Daemon instance.');
}
} elseif ($sourceRoot) {
if (!file_exists($sourceRoot)) {
throw new \UnexpectedValueException("Source root '$sourceRoot' does not exist.");
}
if (!is_dir($sourceRoot)) {
throw new \UnexpectedValueException("Source root '$sourceRoot' is not a directory.");
}
$this->daemon = new Daemon([
'sourceRoot' => $sourceRoot
]);
} else {
throw new \InvalidArgumentException('Must specify either config or sourceRoot');
}

// If the Daemon would be started by the BatchRunner, then don't run it here.
if ($this->isDaemonRunning() && $this->isSysvIPCLoaded()) {
throw new \RuntimeException('Daemon should already be running via BatchDaemon');
}
}

/**
* Start the Daemon. This is expected to run indefinitely.
*/
public function run()
{
$this->daemon->run();
}
}
16 changes: 11 additions & 5 deletions src/Debugger/Daemon.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ class Daemon
* @param array $options [optional] {
* Configuration options.
*
* @type string $sourceRoot The full path to the source root
* @type string $sourceRoot The full path to the source root.
* **Defaults to** the current working directory.
* @type array $clientConfig The options to instantiate the default
* DebuggerClient.
* {@see Google\Cloud\Debugger\DebuggerClient::__construct()}
Expand Down Expand Up @@ -118,6 +119,8 @@ class Daemon
* batch daemon. **Defaults to**
* {@see Google\Cloud\Core\Batch\OpisClosureSerializer} if the
* `opis/closure` library is installed.
* @type bool $register Whether to start the worker in the background
* using the BatchRunner. **Defaults to** false.
* }
*/
public function __construct(array $options = [])
Expand All @@ -130,7 +133,8 @@ public function __construct(array $options = [])
'description' => null,
'debuggee' => null,
'labels' => null,
'metadataProvider' => null
'metadataProvider' => null,
'register' => false
];

$this->setSerializableClientOptions($options);
Expand All @@ -150,9 +154,11 @@ public function __construct(array $options = [])
? $options['storage']
: $this->defaultStorage();

$this->setSimpleJobProperties($options + [
'identifier' => 'debugger-daemon'
]);
if ($options['register']) {
$this->setSimpleJobProperties($options + [
'identifier' => 'debugger-daemon'
]);
}
}

/**
Expand Down
92 changes: 68 additions & 24 deletions src/Debugger/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,71 @@ that project.

## Installation

1. Install the PHP extension from PECL.

```bash
$ pecl install stackdriver_debugger-alpha
```

On Windows, you can download pre-built .dll files [from PECL][pecl-debugger].

You may also need to enable the extension in your `php.ini` file:

```ini
# on Unix
extension=stackdriver_debugger.so

# on Windows
extension=php_stackdriver_debugger.dll
```

1. Install with `composer` or add to your `composer.json`.

```bash
$ composer require google/cloud-debugger
```
```bash
$ composer require google/cloud-debugger
```

2. Run the debugger daemon script in the background.
1. Run the batch daemon script in the background.

```bash
$ vendor/bin/google-cloud-debugger <SOURCE_ROOT>
```
On Unix-based systems that have
[semaphore extensions][semaphore-extensions] installed, run the
[BatchDaemon][batch-daemon]:

```bash
$ vendor/bin/google-cloud-batch daemon
```

On Windows or systems that do not have
[semaphore extensions][semaphore-extensions] installed, run the Debugger
[Daemon][debugger-daemon]:

The `SOURCE_ROOT` is the base location of your deployed application.
```bash
$ vendor/bin/google-cloud-debugger -s <SOURCE_ROOT>
```

3. Include and start the debugger `Agent` as the first action in your
The `SOURCE_ROOT` is the base location of your deployed application.

Alternatively, you can provide a configuration script:

```bash
$ vendor/bin/google-cloud-debugger -c <CONFIG_FILE>
```

1. Include and start the debugger `Agent` as the first action in your
application:

```php
$agent = new Google\Cloud\Debugger\Agent();
```
```php
$agent = new Google\Cloud\Debugger\Agent();
```

If this file is not in your source root, you will need to provide the path to
your application's source root as an optional parameter:
If this file is not in your source root, you will need to provide the path to
your application's source root as an optional parameter:

```php
$agent = new Google\Cloud\Debugger\Agent([
'sourceRoot' => '/path/to/source/root'
]);
```
```php
$agent = new Google\Cloud\Debugger\Agent([
'sourceRoot' => '/path/to/source/root'
]);
```

## Configuration

Expand All @@ -48,10 +84,10 @@ $agent = new Google\Cloud\Debugger\Agent([
Debugger snapshots allow you to capture and inspect the call stack and local
variables in your application without stopping or slowing it down. In general,
you will set breakpoints via the Stackdriver Debugger UI in the
[Cloud Platform Console](https://console.cloud.google.com/debug).
[Cloud Platform Console][debugger-console].

See [Using Debug Snapshots](https://cloud.google.com/debugger/docs/debugging)
for more information on snapshots.
See [Using Debug Snapshots][using-debug-snapshots] for more information on
snapshots.

### Logpoints

Expand All @@ -69,5 +105,13 @@ $agent = new Google\Cloud\Debugger\Agent([
'logger' => new Monolog\Logger('name')
]);
```
See [Using Debug Logpoints](https://cloud.google.com/debugger/docs/logpoints)
for more information on logpoints.
See [Using Debug Logpoints][using-debug-logpoints] for more information on
logpoints.

[semaphore-extensions]: http://php.net/manual/en/book.sem.php
[batch-daemon]: https://github.com/GoogleCloudPlatform/google-cloud-php/blob/master/src/Core/Batch/BatchDaemon.php
[debugger-daemon]: http://googlecloudplatform.github.io/google-cloud-php/#/docs/cloud-debugger/master/debugger/daemon
[pecl-debugger]: https://pecl.php.net/package/stackdriver_debugger
[debugger-console]: https://console.cloud.google.com/debug
[using-debug-snapshots]: https://cloud.google.com/debugger/docs/debugging
[using-debug-logpoints]: https://cloud.google.com/debugger/docs/logpoints
71 changes: 71 additions & 0 deletions src/Debugger/bin/google-cloud-debugger
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/usr/bin/env php
<?php
/**
* Copyright 2017 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

namespace Google\Cloud\Debugger;

// Load the autoloader
if (file_exists(__DIR__ . '/../../../vendor/autoload.php')) {
// Called from local git clone.
require_once __DIR__ . '/../../../vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../../../autoload.php')) {
// Called from google/cloud-core installation.
require_once __DIR__ . '/../../../autoload.php';
} elseif (file_exists(__DIR__ . '/../../../../../autoload.php')) {
// Called from google/cloud installation.
require_once __DIR__ . '/../../../../../autoload.php';
} else {
die('No autoloader found');
}

function showUsageAndDie()
{
$filename = basename(__FILE__);
fwrite(STDERR, <<<EOS
Usage:
$filename [options] | <source-root>

Options:
-c, --config=CONFIG_FILE If specified, load this file which should initialize and return a Debugger\Daemon instance.
-s, --source-root=SOURCE_ROOT Sets the source root for the Daemon. Ignored if --config is specified.


EOS
);
die();
}

if (count($argv) < 2) {
showUsageAndDie();
}

$options = getopt('c:s:', ['config:', 'source-root:'], $optind) + [
'c' => null,
'config' => null,
's' => null,
'source-root' => null
];
try {
$cli = new CliDaemon([
'config' => $options['c'] ?: $options['config'],
'sourceRoot' => $options['s'] ?: $options['source-root'] ?: $argv[1]
]);
} catch (\Exception $e) {
fwrite(STDERR, $e->getMessage() . PHP_EOL);
showUsageAndDie();
}
$cli->run();
5 changes: 4 additions & 1 deletion src/Debugger/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@
},
"archive": {
"exclude": ["/ext"]
}
},
"bin": [
"bin/google-cloud-debugger"
]
}
Loading