Skip to content

Commit 01de8b5

Browse files
authored
Merge pull request #6 from a1comms/homogeneous
Merge Homogeneous
2 parents 79ecae2 + 6b50561 commit 01de8b5

File tree

8 files changed

+445
-3
lines changed

8 files changed

+445
-3
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ Then include the service provider within `config/app.php`.
3333

3434
```php
3535
'providers' => [
36-
A1comms\GaeFlexSupportL5\GaeSupportServiceProvider::class
36+
A1comms\GaeSupportLaravel\GaeSupportServiceProvider::class
3737
];
3838
```
3939

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
"illuminate/session": "~5.1",
1515
"league/flysystem": "~1.0",
1616
"tomwalder/php-gds": "~3.0",
17-
"google/cloud": "dev-batch"
17+
"google/cloud": "v0.32.0",
18+
"madewithlove/illuminate-psr-cache-bridge": "^1.0"
1819
},
1920
"require-dev": {
2021
"phpunit/phpunit": "~4.4"

src/A1comms/GaeSupportLaravel/Artisan/Configurator.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ protected function replaceAppClass($contents)
9999
'A1comms\GaeSupportLaravel\Foundation\Application',
100100
$contents);
101101

102+
$modified = str_replace(
103+
'Laravel\Lumen\Application',
104+
'A1comms\GaeSupportLaravel\Foundation\LumenApplication',
105+
$contents);
106+
102107
if ($contents !== $modified) {
103108
$this->myCommand->info('Replaced the application class in "bootstrap/app.php".');
104109
}

src/A1comms/GaeSupportLaravel/Filesystem/GaeAdapter.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
* slash which is not supported by GCS and an empty directory listing is returned.
2727
* In order to make the check pass the path has to be 'gs://bucket/storage/app/'.
2828
*
29-
* @package A1comms\GaeFlexSupportL5\Filesystem
29+
* @package A1comms\GaeSupportLaravel\Filesystem
3030
*/
3131
class GaeAdapter extends Local
3232
{
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
<?php
2+
3+
namespace A1comms\GaeSupportLaravel\Foundation;
4+
5+
use Symfony\Component\VarDumper\Dumper\HtmlDumper;
6+
use Symfony\Component\VarDumper\Dumper\CliDumper;
7+
use Google\Cloud\Logging\PsrBatchLogger;
8+
use Monolog\Handler\PsrHandler;
9+
use Monolog\Handler\SyslogHandler;
10+
use A1comms\GaeSupportLaravel\Storage\Optimizer;
11+
12+
/**
13+
* class Application
14+
*
15+
* @uses IlluminateApplication
16+
*
17+
* @package A1comms\GaeSupportLaravel\Foundation
18+
*/
19+
class LumenApplication extends \Laravel\Lumen\Application
20+
{
21+
/**
22+
* The GAE app ID.
23+
*
24+
* @var string
25+
*/
26+
protected $appId;
27+
28+
/**
29+
* The GAE app service / module.
30+
*
31+
* @var string
32+
*/
33+
protected $appService;
34+
35+
/**
36+
* The GAE app version.
37+
*
38+
* @var string
39+
*/
40+
protected $appVersion;
41+
42+
/**
43+
* 'true' if running on GAE.
44+
* @var boolean
45+
*/
46+
protected $runningOnGae;
47+
48+
49+
/**
50+
* GAE storage optimizer
51+
*/
52+
protected $optimizer = null;
53+
54+
/**
55+
* Create a new GAE supported application instance.
56+
*
57+
* @param string $basePath
58+
*/
59+
public function __construct($basePath = null)
60+
{
61+
$this->gaeBucketPath = null;
62+
63+
// Load the 'realpath()' function replacement
64+
// for GAE storage buckets.
65+
require_once(__DIR__ . '/gae_realpath.php');
66+
67+
$this->detectGae();
68+
69+
if ( is_gae_std() ) {
70+
$this->configureMonologUsing(function ($monolog) {
71+
$monolog->pushHandler(new SyslogHandler('laravel'));
72+
});
73+
} else if ( is_gae_flex() ) {
74+
$this->configureMonologUsing(function ($monolog) {
75+
$monolog->pushHandler(new PsrHandler(new PsrBatchLogger('app')));
76+
});
77+
}
78+
79+
$this->replaceDefaultSymfonyLineDumpers();
80+
81+
$this->optimizer = new Optimizer($basePath, $this->runningInConsole());
82+
$this->optimizer->bootstrap();
83+
84+
parent::__construct($basePath);
85+
}
86+
87+
88+
/**
89+
* Get the path to the configuration cache file.
90+
*
91+
* @return string
92+
*/
93+
public function getCachedConfigPath()
94+
{
95+
$path = $this->optimizer->getCachedConfigPath();
96+
97+
return $path ?: parent::getCachedConfigPath();
98+
}
99+
100+
101+
/**
102+
* Get the path to the routes cache file.
103+
*
104+
* @return string
105+
*/
106+
public function getCachedRoutesPath()
107+
{
108+
$path = $this->optimizer->getCachedRoutesPath();
109+
110+
return $path ?: parent::getCachedRoutesPath();
111+
}
112+
113+
/**
114+
* Get the path to the cached services.json file.
115+
*
116+
* @return string
117+
*/
118+
public function getCachedServicesPath()
119+
{
120+
$path = $this->optimizer->getCachedServicesPath();
121+
122+
if ($path) {
123+
return $path;
124+
}
125+
126+
if ($this->isRunningOnGae()) {
127+
return $this->storagePath().'/framework/services.json';
128+
}
129+
130+
return parent::getCachedServicesPath();
131+
}
132+
133+
134+
/**
135+
* Detect if the application is running on GAE.
136+
*/
137+
protected function detectGae()
138+
{
139+
if ( ! is_gae() ) {
140+
$this->runningOnGae = false;
141+
$this->appId = null;
142+
$this->appService = null;
143+
$this->appVersion = null;
144+
145+
return;
146+
}
147+
148+
$this->runningOnGae = true;
149+
$this->appId = gae_project();
150+
$this->appService = gae_service();
151+
$this->appVersion = gae_version();
152+
}
153+
154+
/**
155+
* Replaces the default output stream of Symfony's
156+
* CliDumper and HtmlDumper classes in order to
157+
* be able to run on Google App Engine.
158+
*
159+
* 'php://stdout' is used by CliDumper,
160+
* 'php://output' is used by HtmlDumper,
161+
* both are not supported on GAE.
162+
*/
163+
protected function replaceDefaultSymfonyLineDumpers()
164+
{
165+
HtmlDumper::$defaultOutput =
166+
CliDumper::$defaultOutput =
167+
function ($line, $depth, $indentPad) {
168+
if (-1 !== $depth) {
169+
echo str_repeat($indentPad, $depth).$line.PHP_EOL;
170+
}
171+
};
172+
}
173+
174+
/**
175+
* Returns 'true' if running on GAE.
176+
*
177+
* @return bool
178+
*/
179+
public function isRunningOnGae()
180+
{
181+
return $this->runningOnGae;
182+
}
183+
184+
/**
185+
* Returns the GAE app ID.
186+
*
187+
* @return string
188+
*/
189+
public function getGaeAppId()
190+
{
191+
return $this->appId;
192+
}
193+
194+
/**
195+
* Returns the GAE app service / module.
196+
*
197+
* @return string
198+
*/
199+
public function getGaeAppService()
200+
{
201+
return $this->appService;
202+
}
203+
204+
/**
205+
* Returns the GAE app version.
206+
*
207+
* @return string
208+
*/
209+
public function getGaeAppVersion()
210+
{
211+
return $this->appVersion;
212+
}
213+
214+
/**
215+
* Override the storage path
216+
*
217+
* @return string Storage path URL
218+
*/
219+
public function storagePath()
220+
{
221+
if ($this->runningOnGae) {
222+
if (! is_null($this->gaeBucketPath)) {
223+
return $this->gaeBucketPath;
224+
}
225+
$this->gaeBucketPath = Optimizer::getTemporaryPath();
226+
if (! file_exists($this->gaeBucketPath)) {
227+
mkdir($this->gaeBucketPath, 0755, true);
228+
mkdir($this->gaeBucketPath.'/app', 0755, true);
229+
mkdir($this->gaeBucketPath.'/framework', 0755, true);
230+
mkdir($this->gaeBucketPath.'/framework/views', 0755, true);
231+
}
232+
return $this->gaeBucketPath;
233+
}
234+
return parent::storagePath();
235+
}
236+
}
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<?php
2+
3+
namespace A1comms\GaeSupportLaravel\Trace;
4+
5+
use Illuminate\Support\ServiceProvider;
6+
use Google\Cloud\ServiceBuilder;
7+
use Google\Cloud\Trace\TraceClient;
8+
use Google\Cloud\Trace\RequestTracer;
9+
use Google\Cloud\Trace\Reporter\SyncReporter;
10+
//use Google\Cloud\Trace\Reporter\AsyncReporter;
11+
use Google\Cloud\Trace\Reporter\NullReporter;
12+
use Google\Cloud\Trace\Reporter\ReporterInterface;
13+
use A1comms\GaeSupportLaravel\Trace\Reporter\PushQueueReporter;
14+
use Google\Cloud\Trace\Sampler\SamplerInterface;
15+
use Google\Cloud\Trace\Sampler\QpsSampler;
16+
use Google\Cloud\Trace\Sampler\AlwaysOffSampler;
17+
use Psr\Cache\CacheItemPoolInterface;
18+
use Psr\Cache\CacheItemInterface;
19+
use Illuminate\Contracts\Cache\Repository;
20+
use Madewithlove\IlluminatePsrCacheBridge\Laravel\CacheItemPool;
21+
use Madewithlove\IlluminatePsrCacheBridge\Laravel\CacheItem;
22+
23+
class GoogleCloudTraceProvider extends ServiceProvider
24+
{
25+
/**
26+
* Bootstrap the application services.
27+
*
28+
* @return void
29+
*/
30+
public function boot(ReporterInterface $reporter, SamplerInterface $sampler)
31+
{
32+
// don't trace if we're running in the console (i.e. a php artisan command)
33+
if (php_sapi_name() == 'cli') {
34+
return;
35+
}
36+
37+
// start the root span
38+
RequestTracer::start($reporter, [
39+
'sampler' => $sampler
40+
]);
41+
42+
// create a span from the initial start time until now as 'bootstrap'
43+
RequestTracer::startSpan(['name' => 'bootstrap', 'startTime' => LARAVEL_START]);
44+
RequestTracer::endSpan();
45+
46+
// For every Eloquent query execute, create a span with the query as a label
47+
\Event::listen(QueryExecuted::class, function(QueryExecuted $event) {
48+
$startTime = microtime(true) - $event->time * 0.001;
49+
RequestTracer::startSpan([
50+
'name' => $event->connectionName,
51+
'labels' => [
52+
'query' => $event->sql
53+
],
54+
'startTime' => $startTime
55+
]);
56+
RequestTracer::endSpan();
57+
});
58+
}
59+
/**
60+
* Register the application services.
61+
*
62+
* @return void
63+
*/
64+
public function register()
65+
{
66+
$this->app->singleton(ServiceBuilder::class, function($app) {
67+
return new ServiceBuilder($app['config']['services']['google']);
68+
});
69+
$this->app->singleton(TraceClient::class, function($app) {
70+
return $app->make(ServiceBuilder::class)->trace();
71+
});
72+
$this->app->singleton(ReporterInterface::class, function($app) {
73+
if ( is_gae_std() )
74+
{
75+
return new PushQueueReporter();
76+
}
77+
else if ( is_gae_flex() )
78+
{
79+
// return new AsyncReporter([
80+
// 'clientConfig' => $app['config']['services']['google'],
81+
// ]);
82+
return new SyncReporter($app->make(TraceClient::class));
83+
}
84+
85+
return new NullReporter();
86+
});
87+
$this->app->singleton(SamplerInterface::class, function($app) {
88+
if ( is_gae_std() )
89+
{
90+
return new AlwaysOffSampler();
91+
}
92+
93+
return new QpsSampler(
94+
$app->make(CacheItemPoolInterface::class),
95+
['cacheItemClass' => get_class($app->make(CacheItemInterface::class))]
96+
);
97+
});
98+
$this->app->bind(CacheItemPoolInterface::class, function () {
99+
$repository = $this->app->make(Repository::class);
100+
return new CacheItemPool($repository);
101+
});
102+
$this->app->bind(CacheItemInterface::class, function () {
103+
return new CacheItem('_');
104+
});
105+
}
106+
public function provides()
107+
{
108+
return [
109+
ServiceBuilder::class,
110+
TraceClient::class,
111+
ReporterInterface::class,
112+
SamplerInterface::class
113+
];
114+
}
115+
}

0 commit comments

Comments
 (0)