Skip to content

Commit b65cb81

Browse files
authored
Add stackdriver to symfony php72 (GoogleCloudPlatform#817)
1 parent 45b1ce8 commit b65cb81

File tree

13 files changed

+334
-37
lines changed

13 files changed

+334
-37
lines changed

appengine/php72/laravel-framework/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -133,15 +133,15 @@ Logging and Error Reporting:
133133

134134
You can write logs to Stackdriver Logging from PHP applications by using the Stackdriver Logging library for PHP directly.
135135

136-
1. First, create a custom logger in `app/Logging/CreateCustomLogger.php`:
136+
1. First, create a custom logger in `app/Logging/CreateStackdriverLogger.php`:
137137
```php
138138
namespace App\Logging;
139139

140140
use Google\Cloud\Logging\LoggingClient;
141141
use Monolog\Handler\PsrHandler;
142142
use Monolog\Logger;
143143

144-
class CreateCustomLogger
144+
class CreateStackdriverLogger
145145
{
146146
/**
147147
* Create a custom Monolog instance.
@@ -168,7 +168,7 @@ You can write logs to Stackdriver Logging from PHP applications by using the Sta
168168
// Add the following lines to integrate with Stackdriver:
169169
'stackdriver' => [
170170
'driver' => 'custom',
171-
'via' => App\Logging\CreateCustomLogger::class,
171+
'via' => App\Logging\CreateStackdriverLogger::class,
172172
'level' => 'debug',
173173
],
174174
```

appengine/php72/laravel-framework/composer.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
{
22
"require-dev": {
33
"google/cloud-tools": "^0.8.1",
4-
"symfony\/process": "~2.8|~3.0",
54
"monolog\/monolog": "^1.19",
65
"google/cloud-logging": "^1.14"
76
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public function testHomepage()
5757
$this->assertContains('Laravel', $resp->getBody()->getContents());
5858
}
5959

60-
public function testNormalLog()
60+
public function testLogging()
6161
{
6262
// bump up the retry count because logs can take a bit to show up
6363
$this->eventuallyConsistentRetryCount = 5;
@@ -92,7 +92,7 @@ public function testNormalLog()
9292
});
9393
}
9494

95-
public function testErrorLog()
95+
public function testErrorReporting()
9696
{
9797
$this->eventuallyConsistentRetryCount = 5;
9898
$logging = new LoggingClient([

appengine/php72/symfony-framework/README.md

Lines changed: 62 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ to App Engine Standard for PHP 7.2. You will learn how to:
99
1. Set up a [Cloud SQL][cloud-sql] database
1010
1. Configure Doctrine to communicate with Cloud SQL
1111

12-
> **Note**: This repository is just a tutorial and is not a Symfony project in
12+
> **Note**: This repository is just a tutorial and is not a Symfony project in
1313
and of itself. The steps will require you to set up a new Symfony project in a
1414
separate directory.
15-
15+
1616
## Prerequisites
1717

1818
1. [Create a project][create-project] in the Google Cloud Platform Console
@@ -205,12 +205,66 @@ database. This tutorial uses the database name `symfonydb` and the username
205205

206206
gcloud app deploy
207207

208-
### What's Next
208+
## Set up Stackdriver Logging and Error Reporting
209+
210+
Install the Google Cloud libraries for Stackdriver integration:
211+
212+
```sh
213+
# Set the environment variable below to the local path to your symfony project
214+
SYMFONY_PROJECT_PATH="/path/to/my-symfony-project"
215+
cd $SYMFONY_PROJECT_PATH
216+
composer require google/cloud-logging google/cloud-error-reporting
217+
```
218+
219+
### Copy over App Engine files
220+
221+
For your Symfony application to integrate with Stackdriver Logging and Error Handling,
222+
you will need to copy over the `monolog.yaml` config file and the `ExceptionSubscriber.php`
223+
Exception Subscriber:
224+
225+
```sh
226+
# clone the Google Cloud Platform PHP samples repo somewhere
227+
cd /path/to/php-samples
228+
git clone https://github.com/GoogleCloudPlatform/php-docs-samples
229+
230+
# enter the directory for the symfony framework sample
231+
cd appengine/php72/symfony-framework/
232+
233+
# copy monolog.yaml into your Symfony project
234+
cp config/packages/prod/monolog.yaml \
235+
$SYMFONY_PROJECT_PATH/config/packages/prod/
236+
237+
# copy ExceptionSubscriber.php into your Symfony project
238+
cp src/EventSubscriber/ExceptionSubscriber.php \
239+
$SYMFONY_PROJECT_PATH/src/EventSubscriber
240+
```
241+
242+
The two files needed are as follows:
243+
244+
1. [`config/packages/prod/monolog.yaml`](app/config/packages/prod/monolog.yaml) - Adds Stackdriver Logging to your Monolog configuration.
245+
1. [`src/EventSubscriber/ExceptionSubscriber.php`](src/EventSubscriber/ExceptionSubscriber.php) - Event subscriber which sends exceptions to Stackdriver Error Reporting.
246+
247+
If you'd like to test the logging and error reporting, you can also copy over `LoggingController.php`, which
248+
exposes the routes `/en/logging/notice` and `/en/logging/exception` for ensuring your logs are being sent to
249+
Stackdriver:
250+
251+
```
252+
# copy LoggingController.php into your Symfony project
253+
cp src/Controller/LoggingController.php \
254+
$SYMFONY_PROJECT_PATH/src/Controller
255+
```
256+
257+
1. [`src/Controller/LoggingController.php`](src/Controller/LoggingController.php) - Controller for testing logging and exceptions.
258+
259+
### View application logs and errors
209260

210-
1. Check out the [Databases and the Doctrine ORM][symfony-doctrine] documentation for Symfony.
211-
1. View a [Symfony Demo Application][symfony-sample-app] for App Engine Flex.
261+
Once you've redeployed your application using `gcloud app deploy`, you'll be able to view
262+
Application logs in the [Stackdriver Logging UI][stackdriver-logging-ui], and errors in
263+
the [Stackdriver Error Reporting UI][stackdriver-errorreporting-ui]! If you copied over the
264+
`LoggingController.php` file, you can test this by pointing your browser to
265+
`https://YOUR_PROJECT_ID.appspot.com/en/logging/notice` and
266+
`https://YOUR_PROJECT_ID.appspot.com/en/logging/exception`
212267

213-
[php-gcp]: https://cloud.google.com/php
214268
[cloud-sdk]: https://cloud.google.com/sdk/
215269
[cloud-build]: https://cloud.google.com/cloud-build/
216270
[cloud-sql]: https://cloud.google.com/sql/docs/
@@ -219,14 +273,12 @@ database. This tutorial uses the database name `symfonydb` and the username
219273
[cloud-sql-apis]:https://pantheon.corp.google.com/apis/library/sqladmin.googleapis.com/?pro
220274
[create-project]: https://cloud.google.com/resource-manager/docs/creating-managing-projects
221275
[enable-billing]: https://support.google.com/cloud/answer/6293499?hl=en
222-
[php-gcp]: https://cloud.google.com/php
223276
[symfony]: http://symfony.com
224277
[symfony-install]: http://symfony.com/doc/current/setup.html
225278
[symfony-welcome]: https://symfony.com/doc/current/_images/welcome.png
226-
[composer-json]: https://storage.googleapis.com/gcp-community/tutorials/run-symfony-on-appengine-flexible/composer-json.png
227-
[symfony-doctrine]: https://symfony.com/doc/current/doctrine.html
228-
[symfony-sample-app]: https://github.com/bshaffer/symfony-on-app-engine-flex
229279
[symfony-demo]: https://github.com/symfony/demo
230280
[symfony-secret]: http://symfony.com/doc/current/reference/configuration/framework.html#secret
231281
[symfony-env]: https://symfony.com/doc/current/configuration/environments.html#executing-an-application-in-different-environments
232282
[symfony-override-cache]: https://symfony.com/doc/current/configuration/override_dir_structure.html#override-the-cache-directory
283+
[stackdriver-logging-ui]: https://console.cloud.google.com/logs
284+
[stackdriver-errorreporting-ui]: https://console.cloud.google.com/errors

appengine/php72/symfony-framework/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
"require-dev": {
66
"google/cloud-tools": "^0.8.2",
77
"monolog/monolog": "^1.19",
8-
"nikic/php-parser": "^4.0"
8+
"nikic/php-parser": "^4.0",
9+
"google/cloud-logging": "^1.14"
910
}
1011
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
monolog:
2+
handlers:
3+
main:
4+
type: fingers_crossed
5+
action_level: error
6+
handler: nested
7+
excluded_http_codes: [404]
8+
nested:
9+
type: stream
10+
path: "%kernel.logs_dir%/%kernel.environment%.log"
11+
level: debug
12+
console:
13+
type: console
14+
process_psr_3_messages: false
15+
channels: ["!event", "!doctrine"]
16+
deprecation:
17+
type: stream
18+
path: "%kernel.logs_dir%/%kernel.environment%.deprecations.log"
19+
deprecation_filter:
20+
type: filter
21+
handler: deprecation
22+
max_level: info
23+
channels: ["php"]
24+
# [START add_stackdriver_to_symfony_monolog]
25+
google_cloud:
26+
type: service
27+
id: monolog_psr_batch_logger
28+
29+
services:
30+
# Monolog wrapper
31+
monolog_psr_batch_logger:
32+
class: Monolog\Handler\PsrHandler
33+
arguments: ['@google_cloud_stackdriver_psr_batch_logger']
34+
35+
# PsrBatchLogger
36+
google_cloud_stackdriver_psr_batch_logger:
37+
class: Google\Cloud\Logging\PsrLogger
38+
factory: ['Google\Cloud\Logging\LoggingClient', 'psrBatchLogger']
39+
arguments: ['app']
40+
# [END add_stackdriver_to_symfony_monolog]

appengine/php72/symfony-framework/phpunit.xml.dist

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
See the License for the specific language governing permissions and
1515
limitations under the License.
1616
-->
17-
<phpunit bootstrap="vendor/autoload.php">
17+
<phpunit bootstrap="test/bootstrap.php">
1818
<testsuites>
19-
<testsuite name="AppEngine for PHP 7.2 Symfony Framework tests">
19+
<testsuite name="AppEngine for PHP 7.2 Symfony Framework tests">
2020
<directory>testdirectory>
2121
testsuite>
2222
testsuites>
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
2+
3+
/**
4+
* Copyright 2019 Google Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
namespace App\Controller;
20+
21+
use Psr\Log\LoggerInterface;
22+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
23+
use Symfony\Component\HttpFoundation\Response;
24+
use Symfony\Component\Routing\Annotation\Route;
25+
use Exception;
26+
27+
/**
28+
* Controller used to test Stackdriver Logging integration on Google Cloud Platform
29+
*
30+
* @Route("/logging")
31+
*
32+
* @author Brent Shaffer
33+
*/
34+
class LoggingController extends AbstractController
35+
{
36+
/**
37+
* @Route("/notice/{token}", defaults={"token"=0}, methods={"GET"})
38+
*/
39+
public function notice(LoggerInterface $logger, $token): Response
40+
{
41+
$logger->notice("Hello my log, token: $token");
42+
43+
return $this->render('default/homepage.html.twig');
44+
}
45+
46+
/**
47+
* @Route("/exception/{token}", defaults={"token"=0}, methods={"GET"})
48+
*/
49+
public function exception($token): Response
50+
{
51+
throw new Exception("Intentional exception, token: $token");
52+
}
53+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
2+
3+
/**
4+
* Copyright 2019 Google Inc.
5+
*
6+
* Licensed under the Apache License, Version 2.0 (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
# [START error_reporting_setup_php_symfony]
20+
// src/EventSubscriber/ExceptionSubscriber.php
21+
namespace App\EventSubscriber;
22+
23+
use Google\Cloud\ErrorReporting\Bootstrap;
24+
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
25+
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
26+
use Symfony\Component\HttpKernel\KernelEvents;
27+
28+
/**
29+
* EventSubscrber used to log all exceptions to Stackdriver Error Reporting on Google Cloud Platform
30+
*
31+
* @author Brent Shaffer
32+
*/
33+
class ExceptionSubscriber implements EventSubscriberInterface
34+
{
35+
public static function getSubscribedEvents()
36+
{
37+
// return the subscribed events, their methods and priorities
38+
return [KernelEvents::EXCEPTION => [
39+
['logException', 0]
40+
]];
41+
}
42+
43+
public function logException(GetResponseForExceptionEvent $event)
44+
{
45+
$exception = $event->getException();
46+
Bootstrap::init();
47+
Bootstrap::exceptionHandler($exception);
48+
}
49+
}
50+
# [END error_reporting_setup_php_symfony]

appengine/php72/symfony-framework/test/DeployDoctrineTest.php

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@
2020
use Google\Cloud\TestUtils\TestTrait;
2121
use PHPUnit\Framework\TestCase;
2222

23-
require_once __DIR__ . '/lib/SymfonyDeploymentTrait.php';
24-
2523
class DeployDoctrineTest extends TestCase
2624
{
2725
use TestTrait;
28-
use SymfonyDeploymentTrait;
26+
use DeploySymfonyTrait;
2927

3028
public static function beforeDeploy()
3129
{
30+
// ensure logging output is displayed in phpunit
31+
self::$logger = new \Monolog\Logger('phpunit');
32+
3233
$dbConn = self::requireEnv('SYMFONY_CLOUDSQL_CONNECTION_NAME');
3334
$dbName = self::requireEnv('SYMFONY_DB_DATABASE');
3435
$dbPass = self::requireEnv('SYMFONY_DB_PASSWORD');

appengine/php72/symfony-framework/test/lib/SymfonyDeploymentTrait.php renamed to appengine/php72/symfony-framework/test/DeploySymfonyTrait.php

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,12 @@
2626
use PhpParser\Node\Stmt\ClassMethod;
2727
use PhpParser\NodeTraverser;
2828
use PhpParser\NodeVisitorAbstract;
29-
use Monolog\Logger;
3029

31-
trait SymfonyDeploymentTrait
30+
trait DeploySymfonyTrait
3231
{
3332
use AppEngineDeploymentTrait;
3433
use ExecuteCommandTrait;
3534

36-
/**
37-
* @beforeClass
38-
*/
39-
public static function setMonologLogger()
40-
{
41-
// ensure logging output is displayed in phpunit
42-
self::$logger = new Logger('phpunit');
43-
}
44-
4535
private static function createSymfonyProject()
4636
{
4737
$tmpDir = sys_get_temp_dir() . '/test-' . FileUtil::randomName(8);
@@ -56,7 +46,7 @@ private static function createSymfonyProject()
5646
self::executeProcess($process);
5747

5848
// move app.yaml for the sample to the new symfony installation
59-
copy(__DIR__ . '/../../app.yaml', $tmpDir . '/app.yaml');
49+
self::copyFiles(['app.yaml'], $tmpDir);
6050

6151
// Remove the scripts from composer so they do not error out in the
6252
// Cloud Build environment.
@@ -104,4 +94,13 @@ public function enterNode(Node $node)
10494
$prettyPrinter = new PrettyPrinter\Standard();
10595
file_put_contents($kernelFile, $prettyPrinter->prettyPrintFile($ast));
10696
}
97+
98+
private static function copyFiles(array $files, $dir)
99+
{
100+
foreach ($files as $file) {
101+
$source = sprintf('%s/../%s', __DIR__, $file);
102+
$target = sprintf('%s/%s', $dir, $file);
103+
copy($source, $target);
104+
}
105+
}
107106
}

0 commit comments

Comments
 (0)