Skip to content

Commit c9b4af6

Browse files
authored
Add Stackdriver for App Engine Standard / PHP 72 (GoogleCloudPlatform#796)
1 parent 8564915 commit c9b4af6

File tree

8 files changed

+372
-16
lines changed

8 files changed

+372
-16
lines changed

appengine/php72/laravel-framework/README.md

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,92 @@ Laravel, you need to manually add the `DB_SOCKET` value to
122122
1. Replace each instance of `YOUR_DB_PASSWORD` and `YOUR_CONNECTION_NAME`
123123
with the values you created for your Cloud SQL instance above.
124124

125+
## Set up Stackdriver Logging and Error Reporting
126+
127+
Before we begin, install both of the Google Cloud client libraries for Stackdriver
128+
Logging and Error Reporting:
129+
130+
composer require google/cloud-logging google/cloud-error-reporting
131+
132+
### Stackdriver Logging
133+
134+
You can write logs to Stackdriver Logging from PHP applications by using the Stackdriver Logging library for PHP directly.
135+
136+
1. First, create a custom logger in `app/Logging/CreateCustomLogger.php`:
137+
```php
138+
namespace App\Logging;
139+
140+
use Google\Cloud\Logging\LoggingClient;
141+
use Monolog\Handler\PsrHandler;
142+
use Monolog\Logger;
143+
144+
class CreateCustomLogger
145+
{
146+
/**
147+
* Create a custom Monolog instance.
148+
*
149+
* @param array $config
150+
* @return \Monolog\Logger
151+
*/
152+
public function __invoke(array $config)
153+
{
154+
$logName = isset($config['logName']) ? $config['logName'] : 'app';
155+
$psrLogger = LoggingClient::psrBatchLogger($logName);
156+
$handler = new PsrHandler($psrLogger);
157+
$logger = new Logger($logName, [$handler]);
158+
return $logger;
159+
}
160+
}
161+
```
162+
163+
1. Next, you'll need to add our new custom logger to `config/logging.php`:
164+
165+
```php
166+
'channels' => [
167+
168+
// Add the following lines to integrate with Stackdriver:
169+
'stackdriver' => [
170+
'driver' => 'custom',
171+
'via' => App\Logging\CreateCustomLogger::class,
172+
'level' => 'debug',
173+
],
174+
```
175+
176+
1. Now you can log to Stackdriver logging anywhere in your application!
177+
178+
```php
179+
Log::info("Hello Stackdriver! This will show up as log level INFO!");
180+
```
181+
182+
### Stackdriver Error Reporting
183+
184+
You can send error reports to Stackdriver Error Reporting from PHP applications by using the
185+
[Stackdriver Error Reporting library for PHP](http://googleapis.github.io/google-cloud-php/#/docs/cloud-error-reporting/v0.12.3/errorreporting/readme).
186+
187+
188+
1. Add the following `use` statement at the beginning of the file `app/Exceptions/Handler.php`:
189+
```php
190+
use Google\Cloud\ErrorReporting\Bootstrap;
191+
```
192+
193+
1. Edit the `report` function in the same file (`app/Exceptions/Handler.php`) as follows:
194+
```php
195+
public function report(Exception $exception)
196+
{
197+
if (isset($_SERVER['GAE_SERVICE'])) {
198+
Bootstrap::init();
199+
Bootstrap::exceptionHandler($exception);
200+
} else {
201+
parent::report($exception);
202+
}
203+
}
204+
```
205+
206+
1. Now any PHP Exception will be logged to Stackdriver Error Reporting!
207+
```php
208+
throw new \Exception('PHEW! We will see this in Stackdriver Error Reporting!');
209+
```
210+
125211
[php-gcp]: https://cloud.google.com/php
126212
[laravel]: http://laravel.com
127213
[laravel-install]: https://laravel.com/docs/5.4/installation
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
3+
namespace App\Exceptions;
4+
5+
use Exception;
6+
use Google\Cloud\ErrorReporting\Bootstrap;
7+
use Illuminate\Foundation\Exceptions\Handler as ExceptionHandler;
8+
9+
class Handler extends ExceptionHandler
10+
{
11+
/**
12+
* A list of the exception types that are not reported.
13+
*
14+
* @var array
15+
*/
16+
protected $dontReport = [
17+
//
18+
];
19+
20+
/**
21+
* A list of the inputs that are never flashed for validation exceptions.
22+
*
23+
* @var array
24+
*/
25+
protected $dontFlash = [
26+
'password',
27+
'password_confirmation',
28+
];
29+
30+
/**
31+
* Report or log an exception.
32+
*
33+
* This is a great spot to send exceptions to Sentry, Bugsnag, etc.
34+
*
35+
* @param \Exception $exception
36+
* @return void
37+
*/
38+
# [START error_reporting_setup_php_laravel]
39+
public function report(Exception $exception)
40+
{
41+
if (isset($_SERVER['GAE_SERVICE'])) {
42+
// Ensure Stackdriver is initialized and handle the exception
43+
Bootstrap::init();
44+
Bootstrap::exceptionHandler($exception);
45+
} else {
46+
parent::report($exception);
47+
}
48+
}
49+
# [END error_reporting_setup_php_laravel]
50+
51+
/**
52+
* Render an exception into an HTTP response.
53+
*
54+
* @param \Illuminate\Http\Request $request
55+
* @param \Exception $exception
56+
* @return \Illuminate\Http\Response
57+
*/
58+
public function render($request, Exception $exception)
59+
{
60+
return parent::render($request, $exception);
61+
}
62+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
3+
namespace App\Logging;
4+
5+
use Google\Cloud\Logging\LoggingClient;
6+
use Monolog\Handler\PsrHandler;
7+
use Monolog\Logger;
8+
9+
class CreateStackdriverLogger
10+
{
11+
/**
12+
* Create a custom Monolog instance.
13+
*
14+
* @param array $config
15+
* @return \Monolog\Logger
16+
*/
17+
public function __invoke(array $config)
18+
{
19+
$logName = isset($config['logName']) ? $config['logName'] : 'app';
20+
$psrLogger = LoggingClient::psrBatchLogger($logName);
21+
$handler = new PsrHandler($psrLogger);
22+
$logger = new Logger($logName, [$handler]);
23+
return $logger;
24+
}
25+
}

appengine/php72/laravel-framework/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"require-dev": {
33
"google/cloud-tools": "^0.8.1",
44
"symfony\/process": "~2.8|~3.0",
5-
"monolog\/monolog": "^1.19"
5+
"monolog\/monolog": "^1.19",
6+
"google/cloud-logging": "^1.14"
67
}
78
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
2+
3+
return [
4+
5+
/*
6+
|--------------------------------------------------------------------------
7+
| Default Log Channel
8+
|--------------------------------------------------------------------------
9+
|
10+
| This option defines the default log channel that gets used when writing
11+
| messages to the logs. The name specified in this option should match
12+
| one of the channels defined in the "channels" configuration array.
13+
|
14+
*/
15+
16+
'default' => env('LOG_CHANNEL', 'stack'),
17+
18+
/*
19+
|--------------------------------------------------------------------------
20+
| Log Channels
21+
|--------------------------------------------------------------------------
22+
|
23+
| Here you may configure the log channels for your application. Out of
24+
| the box, Laravel uses the Monolog PHP logging library. This gives
25+
| you a variety of powerful log handlers / formatters to utilize.
26+
|
27+
| Available Drivers: "single", "daily", "slack", "syslog",
28+
| "errorlog", "custom", "stack"
29+
|
30+
*/
31+
32+
'channels' => [
33+
'stack' => [
34+
'driver' => 'stack',
35+
'channels' => ['single'],
36+
],
37+
38+
'single' => [
39+
'driver' => 'single',
40+
'path' => storage_path('logs/laravel.log'),
41+
'level' => 'debug',
42+
],
43+
44+
'daily' => [
45+
'driver' => 'daily',
46+
'path' => storage_path('logs/laravel.log'),
47+
'level' => 'debug',
48+
'days' => 7,
49+
],
50+
51+
'slack' => [
52+
'driver' => 'slack',
53+
'url' => env('LOG_SLACK_WEBHOOK_URL'),
54+
'username' => 'Laravel Log',
55+
'emoji' => ':boom:',
56+
'level' => 'critical',
57+
],
58+
59+
'syslog' => [
60+
'driver' => 'syslog',
61+
'level' => 'debug',
62+
],
63+
64+
'errorlog' => [
65+
'driver' => 'errorlog',
66+
'level' => 'debug',
67+
],
68+
69+
'stackdriver' => [
70+
'driver' => 'custom',
71+
'via' => App\Logging\CreateStackdriverLogger::class,
72+
'level' => 'debug',
73+
],
74+
75+
],
76+
77+
];
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
3+
/*
4+
|--------------------------------------------------------------------------
5+
| Web Routes
6+
|--------------------------------------------------------------------------
7+
|
8+
| Here is where you can register web routes for your application. These
9+
| routes are loaded by the RouteServiceProvider within a group which
10+
| contains the "web" middleware group. Now create something great!
11+
|
12+
*/
13+
14+
Route::get('/', function () {
15+
return view('welcome');
16+
});
17+
18+
Route::get('/log/{token}', function ($token) {
19+
Log::info("Hello my log, token: $token");
20+
return view('welcome');
21+
});
22+
23+
Route::get('/exception/{token}', function ($token) {
24+
throw new Exception("Intentional exception, token: $token");
25+
});

appengine/php72/laravel-framework/test/DeployLaravelTrait.php

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,16 +37,10 @@ private static function createLaravelProject()
3737
self::executeProcess($process);
3838

3939
// move the code for the sample to the new laravel installation
40-
$files = [
41-
// '.gcloudignore',
40+
self::copyFiles([
4241
'bootstrap/app.php',
4342
'config/view.php',
44-
];
45-
foreach ($files as $file) {
46-
$source = sprintf('%s/../%s', __DIR__, $file);
47-
$target = sprintf('%s/%s', $tmpDir, $file);
48-
copy($source, $target);
49-
}
43+
], $tmpDir);
5044

5145
// set the directory in gcloud and move there
5246
self::setWorkingDirectory($tmpDir);
@@ -66,4 +60,13 @@ private static function addAppKeyToAppYaml($targetDir)
6660
], file_get_contents($targetDir . '/app.yaml'));
6761
file_put_contents($targetDir . '/app.yaml', $appYaml);
6862
}
63+
64+
private static function copyFiles(array $files, $dir)
65+
{
66+
foreach ($files as $file) {
67+
$source = sprintf('%s/../%s', __DIR__, $file);
68+
$target = sprintf('%s/%s', $dir, $file);
69+
copy($source, $target);
70+
}
71+
}
6972
}

0 commit comments

Comments
 (0)