Skip to content
This repository was archived by the owner on Nov 3, 2020. It is now read-only.

Commit a3f5fd9

Browse files
authored
Merge pull request #14 from nipwaayoni/add-agentbuilder
Add agentbuilder
2 parents c795301 + d777ef0 commit a3f5fd9

File tree

9 files changed

+159
-104
lines changed

9 files changed

+159
-104
lines changed

CHANGELOG

Lines changed: 0 additions & 11 deletions
This file was deleted.

README.md

Lines changed: 13 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ This package is a continuation of the excellent work done by [philkra](https://g
1818
composer require nipwaayoni/elastic-apm-laravel
1919
```
2020

21+
The [nipwaayoni/elastic-apm-php-agent](https://github.com/nipwaayoni/elastic-apm-php-agent) no longer includes and http client. You must ensure a [PSR-18](https://www.php-fig.org/psr/psr-18/) compatible implementation is available. Please see the [agent install guide](https://github.com/nipwaayoni/elastic-apm-php-agent/blob/master/docs/install.md) for more information.
22+
2123
## Service Provider
2224

2325
### Laravel
2426

25-
No need to register service provider manually. It is registered automatically by [package discovery](https://laravel.com/docs/5.6/packages#package-discovery).
27+
If using Laravel >=5.5, registration is done automatically by [package discovery](https://laravel.com/docs/7.x/packages#package-discovery).
28+
29+
This package is not tested or asserted to work with Laravel <5.5.
2630

2731
### Lumen
2832

@@ -73,92 +77,31 @@ based process. We hope to address those issues in a future release.
7377

7478
Spans occur within a Transaction. Spans represent events within the Transaction. Queries made through Laravel's
7579
database layer are automatically added to the Transaction. You can add your own Span events using the `EventTimer`
76-
class from this package.
80+
class from this package. See the docs for [creating spans](docs/creating_spans.md).
7781

7882
Nested Spans are not supported by this package yet.
7983

80-
#### Laravel
81-
82-
Acquire the EventTimer object from the container.
83-
84-
```php
85-
class MyClass
86-
{
87-
/**
88-
* @var EventTimer
89-
*/
90-
private $eventTimer;
91-
92-
public function __construct(EventTimer $eventTimer)
93-
{
94-
$this->eventTimer = $eventTimer;
95-
}
96-
97-
public function runSomeRequest(int $number): AnObject
98-
{
99-
$event = $this->eventTimer->begin('Request the data');
100-
$result = $this->someMethod($number);
101-
$this->eventTimer->finish($event);
102-
103-
return new AnObject($result);
104-
}
105-
}
106-
```
107-
108-
#### Lumen
109-
110-
pending
111-
11284
### Error Events
11385

114-
#### Laravel
115-
116-
In `app/Exceptions/Handler`, add the following to the `report` method:
117-
118-
```php
119-
ElasticApm::captureThrowable($exception);
120-
```
121-
122-
Make sure to import the facade at the top of your file:
123-
124-
```php
125-
use ElasticApm;
126-
```
127-
128-
#### Lumen
129-
130-
pending
86+
The APM service defines exception events as a valid type. Exceptions in your application can be sent to APM in addition to any normal exception handling. See the docs for [exceptions](docs/exceptions.md).
13187

13288
## Agent Configuration
13389

134-
### Laravel
135-
136-
The following environment variables are supported in the default configuration:
90+
You can use a number of environment settings to influence the behavior of this package. At a minimum, you must set the APM server URL and, if applicable, the secret toke:
13791

13892
| Variable | Description |
13993
|-------------------|-------------|
140-
|APM_ACTIVE | `true` or `false` defaults to `true`. If `false`, the agent will collect, but not send, transaction data. |
141-
|APM_APPNAME | Name of the app as it will appear in APM. |
142-
|APM_APPVERSION | Version of the app as it will appear in APM. |
14394
|APM_SERVERURL | URL to the APM intake service. |
14495
|APM_SECRETTOKEN | Secret token, if required. |
145-
|APM_APIVERSION | APM API version, defaults to `v1` (only v1 is supported at this time). |
146-
|APM_USEROUTEURI | `true` or `false` defaults to `false`. The default behavior is to record the URL as sent in the request. This can result in excessive unique entries in APM. Set to `true` to have the agent use the route URL instead. |
147-
|APM_QUERYLOG | `true` or `false` defaults to 'true'. Set to `false` to completely disable query logging, or to `auto` if you would like to use the threshold feature. |
148-
|APM_THRESHOLD | Query threshold in milliseconds, defaults to `200`. If a query takes longer then 200ms, we enable the query log. Make sure you set `APM_QUERYLOG=auto`. |
149-
|APM_BACKTRACEDEPTH | Defaults to `25`. Depth of backtrace in query span. |
150-
|APM_RENDERSOURCE | Defaults to `true`. Include source code in query span. |
15196

152-
You may also publish the `elastic-apm.php` configuration file to change additional settings:
97+
Refer to the [configuration docs](docs/configuration.md) for more information.
15398

154-
```bash
155-
php artisan vendor:publish --tag=config
156-
```
99+
### HTTP Client Customization
157100

158-
Once published, open the `config/elastic-apm.php` file and review the various settings.
101+
It is no longer possible to provide HTTP client options through the APM PHP Agent configuration. If you need to customize the HTTP client, you must implement and configure a suitable client object and properly register it with the Laravel service container. See the "HTTP Client Configuation" section of the [configuration docs](docs/configuration.md).
159102

160-
### Laravel Test Setup
103+
## Laravel Test Setup
161104

162105
Laravel provides classes to support running unit and feature tests with PHPUnit. In most cases, you will want to explicitly disable APM during testing since it is enabled by default. Refer to the Laravel documentation for more information (https://laravel.com/docs/5.7/testing).
163106

164-
Because the APM agent checks it's active status using a strict boolean type, you must ensure your `APM_ACTIVE` value is a boolean `false` rather than simply a falsy value. The best way to accomplish this is to create an `.env.testing` file and include `APM_ACTIVE=false`, along with any other environment settings required for your tests. This file should be safe to include in your SCM.
107+
Because the APM agent checks its active status using a strict boolean type, you must ensure your `APM_ACTIVE` value is a boolean `false` rather than simply a falsy value. The best way to accomplish this is to create an `.env.testing` file and include `APM_ACTIVE=false`, along with any other environment settings required for your tests. This file should be safe to include in your SCM.

composer.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@
1212
"license": "MIT",
1313
"require": {
1414
"php": ">= 7.2",
15-
"illuminate/database": ">= 6.0 < 8",
16-
"illuminate/http": ">= 6.0 < 8",
17-
"illuminate/routing": ">= 6.0 < 8",
18-
"illuminate/support": ">= 6.0 < 8",
19-
"nipwaayoni/elastic-apm-php-agent": "7.1.0-rc1",
15+
"nipwaayoni/elastic-apm-php-agent": "^7.1",
2016
"ramsey/uuid": ">= 3.0 < 5.0"
2117
},
2218
"require-dev": {

docs/breaking_changes.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Breaking Changes
2+
3+
## 7.x
4+
5+
1. The [Elastic APM PHP Agent](https://github.com/nipwaayoni/elastic-apm-php-agent) minimum version has been updated.
6+
2. It is no longer recommended to call `Agent::send()` in `Exceptions\Handler::report()`. This will likely result in duplicate reporting of exceptions.
7+
3. The `elastic-apm.env` settings have been redefined. This key now contains the allowed list of environment variables to include the APM context. The application environment is now set in `elastic-apm.environment`. If you previously published the `config/elastic-apm.php` file, you must make certain it is updated.
8+
4. The [Elastic APM PHP Agent](https://github.com/nipwaayoni/elastic-apm-php-agent) no longer provides an HTTP client implementation. Please see the [agent install guide](https://github.com/nipwaayoni/elastic-apm-php-agent/blob/master/docs/install.md) for more information. The configuration passed to the `Agent` can no longer contain the `httpClient` key. If you previously published the `config/elastic-apm.php` file, you must remove that key.
9+
5. The method of creating span events has changed. See the [creating spans](creating_spans.md) documentation.

docs/configuration.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Configuration
2+
3+
The following environment variables are supported in the default configuration:
4+
5+
| Variable | Description |
6+
|-------------------|-------------|
7+
|APM_ACTIVE | `true` or `false` defaults to `true`. If `false`, the agent will collect, but not send, transaction data. |
8+
|APM_APPNAME | Name of the app as it will appear in APM. |
9+
|APM_APPVERSION | Version of the app as it will appear in APM. |
10+
|APM_SERVERURL | URL to the APM intake service. |
11+
|APM_SECRETTOKEN | Secret token, if required. |
12+
|APM_APIVERSION | APM API version, defaults to `v2` (only v2 is supported at this time). |
13+
|APM_USEROUTEURI | `true` or `false` defaults to `false`. The default behavior is to record the URL as sent in the request. This can result in excessive unique entries in APM. Set to `true` to have the agent use the route URL instead. |
14+
|APM_QUERYLOG | `true` or `false` defaults to 'true'. Set to `false` to completely disable query logging, or to `auto` if you would like to use the threshold feature. |
15+
|APM_THRESHOLD | Query threshold in milliseconds, defaults to `200`. If a query takes longer then 200ms, we enable the query log. Make sure you set `APM_QUERYLOG=auto`. |
16+
|APM_BACKTRACEDEPTH | Defaults to `25`. Depth of backtrace in query span. |
17+
|APM_RENDERSOURCE | Defaults to `true`. Include source code in query span. |
18+
19+
You may also publish the `elastic-apm.php` configuration file to change additional settings:
20+
21+
```bash
22+
php artisan vendor:publish --tag=config
23+
```
24+
25+
Once published, open the `config/elastic-apm.php` file and review the various settings.
26+
27+
## HTTP Client Configuration
28+
29+
If you need to customize the HTTP client, you must create a [PSR-18](https://www.php-fig.org/psr/psr-18/) compatible implementation and bind it in the Laravel service container. For now, we will use a GuzzleHttp adapter from the PHP-HTTP project.
30+
31+
```bash
32+
composer require http-interop/http-factory-guzzle php-http/guzzle6-adapter
33+
```
34+
35+
The following example demonstrates how to create a GuzzleHttp client that will not verify server certificates. Once you create the client, bind it in the service container under the `ElasticApmHttpClient` abstract.
36+
37+
```php
38+
$this->app->bind('ElasticApmHttpClient', function () {
39+
// Create the configured client
40+
$client = new \GuzzleHttp\Client([
41+
'verify' => false,
42+
// other client options
43+
]);
44+
45+
// Wrap the client object in the adapter and return it
46+
return new \Http\Adapter\Guzzle6\Client($client);
47+
});
48+
49+
```
50+
51+
If the service container has a binding for `ElasticApmHttpClient`, the concrete implementation will be retrieved and passed into the `Agent`.

docs/creating_spans.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Creating Spans
2+
3+
The current event implementation creates a single APM transaction to represent the Laravel Request/Response. You can create APM span events to represent discrete actions within the transaction. The `\Nipwaayoni\ElasticApmLaravel\Apm\EventTimer` class facilitates making spans.
4+
5+
```php
6+
class MyClass
7+
{
8+
/**
9+
* @var \Nipwaayoni\ElasticApmLaravel\Apm\EventTimer
10+
*/
11+
private $eventTimer;
12+
13+
public function __construct(\Nipwaayoni\ElasticApmLaravel\Apm\EventTimer $eventTimer)
14+
{
15+
$this->eventTimer = $eventTimer;
16+
}
17+
18+
public function runSomeRequest(int $number): MyObject
19+
{
20+
$event = $this->eventTimer->begin('Request the data');
21+
$result = $this->someMethod($number);
22+
$this->eventTimer->finish($event);
23+
24+
return new MyObject($result);
25+
}
26+
}
27+
```
28+
29+
The `EventTimer` makes the transaction the parent event of all spans.

docs/exceptions.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Exceptions
2+
3+
Laravel provides a convenient method for working with application exceptions which we can leverage to send Exceptions to APM. In `app/Exceptions/Handler`, add the following to the `report` method:
4+
5+
```php
6+
ElasticApm::captureThrowable($exception);
7+
```
8+
9+
Make sure to import the facade at the top of your file:
10+
11+
```php
12+
use ElasticApm;
13+
```
14+
15+
The collected Exceptions will be sent when `Agent::send()` is called in the middleware.
16+
17+
Note that previous versions of this package suggested calling `Agent::send()` explicitly in `Handler::report()`. The was related to APM < 7 intake and is no longer suggested as it may lead to duplicate events.
18+
19+
Note that the Laravel exception handler is only aware of exceptions generated after the Laravel framework is minimally bootstrapped. An error preventing the proper executation of the bootstrap process will not be captured in `Handler::report()`.

src/Providers/ElasticApmServiceProvider.php

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
use Illuminate\Support\Str;
99
use Illuminate\Support\Arr;
1010
use Nipwaayoni\Agent;
11+
use Nipwaayoni\AgentBuilder;
12+
use Nipwaayoni\Config;
1113
use Nipwaayoni\ElasticApmLaravel\Contracts\VersionResolver;
1214
use Nipwaayoni\Helper\Timer;
15+
use Psr\Container\ContainerInterface;
1316

1417
class ElasticApmServiceProvider extends ServiceProvider
1518
{
@@ -49,21 +52,44 @@ public function register()
4952
);
5053

5154
$this->app->singleton(Agent::class, function ($app) {
52-
return new Agent(
55+
$container = resolve(ContainerInterface::class);
56+
57+
$builder = new AgentBuilder();
58+
$builder->withConfig(new Config(
5359
array_merge(
5460
[
61+
'active' => config('elastic-apm.active'),
5562
'framework' => 'Laravel',
5663
'frameworkVersion' => app()->version(),
5764
],
58-
[
59-
'active' => config('elastic-apm.active'),
60-
'httpClient' => config('elastic-apm.httpClient'),
61-
],
6265
$this->getAppConfig(),
63-
config('elastic-apm.env'),
6466
config('elastic-apm.server')
6567
)
66-
);
68+
));
69+
70+
$builder->withEnvData(config('elastic-apm.env'));
71+
72+
if ($container->has('ElasticApmEventFactory')) {
73+
$builder->withEventFactory($container->get('ElasticApmEventFactory'));
74+
}
75+
76+
if ($container->has('ElasticApmTransactionStore')) {
77+
$builder->withTransactionStore($container->get('ElasticApmTransactionStore'));
78+
}
79+
80+
if ($container->has('ElasticApmHttpClient')) {
81+
$builder->withHttpClient($container->get('ElasticApmHttpClient'));
82+
}
83+
84+
if ($container->has('ElasticApmRequestFactory')) {
85+
$builder->withRequestFactory($container->get('ElasticApmRequestFactory'));
86+
}
87+
88+
if ($container->has('ElasticApmStreamFactory')) {
89+
$builder->withStreamFactory($container->get('ElasticApmStreamFactory'));
90+
}
91+
92+
return $builder->build();
6793
});
6894

6995
$this->startTime = $this->app['request']->server('REQUEST_TIME_FLOAT') ?? microtime(true);

src/config/elastic-apm.php

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
return [
44
// Sets whether the apm reporting should be active or not
55
'active' => env('APM_ACTIVE', true),
6+
'environment' => env('APM_ENVIRONMENT', 'development'),
67

78
'app' => [
89
// The app name that will identify your app in Kibana / Elastic APM
@@ -12,16 +13,8 @@
1213
'appVersion' => env('APM_APPVERSION', ''),
1314
],
1415

15-
'env' => [
16-
// whitelist environment variables OR send everything
17-
'env' => ['DOCUMENT_ROOT', 'REMOTE_ADDR'],
18-
//'env' => []
19-
// Application environment
20-
'environment' => env('APM_ENVIRONMENT', 'development'),
21-
],
22-
23-
// GuzzleHttp\Client options (http://docs.guzzlephp.org/en/stable/request-options.html#request-options)
24-
'httpClient' => [],
16+
// list allowed environment variables OR empty array to send everything
17+
'env' => ['DOCUMENT_ROOT', 'REMOTE_ADDR'],
2518

2619
'server' => [
2720
// The apm-server to connect to
@@ -31,7 +24,7 @@
3124
'secretToken' => env('APM_SECRETTOKEN', null),
3225

3326
// API version of the apm agent you connect to
34-
'apmVersion' => env('APM_APIVERSION', 'v1'),
27+
'apmVersion' => env('APM_APIVERSION', 'v2'),
3528

3629
// Hostname of the system the agent is running on.
3730
'hostname' => gethostname(),

0 commit comments

Comments
 (0)