diff --git a/README.md b/README.md index eac3e2f..4c31e96 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,26 @@ $app->middleware([ ]); ``` +## Spans +### Laravel +A Transaction object is made available via the dependency container and can be used to start a +new span at any point in the application. The Span will automatically add itself to the Transaction +when it is ended. + +```php +// Use any normal Laravel method of resolving the dependency +$transaction = app(\PhilKra\ElasticApmLaravel\Apm\Transaction::class); + +$span = $transaction->startNewSpan('My Span', 'app.component_name'); + +// do some stuff + +$span->end(); +``` +### Lumen + +pending + ## Error/Exception Handling ### Laravel @@ -53,17 +73,19 @@ not tested yet. The following environment variables are supported in the default configuration: -| Variable | Description | -|------------------|-------------| -|APM_ACTIVE | `true` or `false` defaults to `true`. If `false`, the agent will collect, but not send, transaction data. | -|APM_APPNAME | Name of the app as it will appear in APM. | -|APM_APPVERSION | Version of the app as it will appear in APM. | -|APM_SERVERURL | URL to the APM intake service. | -|APM_SECRETTOKEN | Secret token, if required. | -|APM_APIVERSION | APM API version, defaults to `v1` (only v1 is supported at this time). | -|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. | -|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. | -|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`. | +| Variable | Description | +|-------------------|-------------| +|APM_ACTIVE | `true` or `false` defaults to `true`. If `false`, the agent will collect, but not send, transaction data. | +|APM_APPNAME | Name of the app as it will appear in APM. | +|APM_APPVERSION | Version of the app as it will appear in APM. | +|APM_SERVERURL | URL to the APM intake service. | +|APM_SECRETTOKEN | Secret token, if required. | +|APM_APIVERSION | APM API version, defaults to `v1` (only v1 is supported at this time). | +|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. | +|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. | +|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`. | +|APM_BACKTRACEDEPTH | Defaults to `25`. Depth of backtrace in query span. | +|APM_RENDERSOURCE | Defaults to `true`. Include source code in query span. | You may also publish the `elastic-apm.php` configuration file to change additional settings: diff --git a/config/elastic-apm.php b/config/elastic-apm.php index 5f1f841..ec43ebc 100644 --- a/config/elastic-apm.php +++ b/config/elastic-apm.php @@ -14,8 +14,10 @@ 'env' => [ // whitelist environment variables OR send everything - 'env' => ['DOCUMENT_ROOT', 'REMOTE_ADDR'] + 'env' => ['DOCUMENT_ROOT', 'REMOTE_ADDR'], //'env' => [] + // Application environment + 'environment' => env('APM_ENVIRONMENT', 'development'), ], // GuzzleHttp\Client options (http://docs.guzzlephp.org/en/stable/request-options.html#request-options) @@ -44,10 +46,10 @@ 'spans' => [ // Depth of backtraces - 'backtraceDepth'=> 25, + 'backtraceDepth'=> env('APM_BACKTRACEDEPTH', 25), // Add source code to span - 'renderSource' => true, + 'renderSource' => env('APM_RENDERSOURCE', true), 'querylog' => [ // Set to false to completely disable query logging, or to 'auto' if you would like to use the threshold feature. diff --git a/src/Apm/Span.php b/src/Apm/Span.php new file mode 100644 index 0000000..f9f951f --- /dev/null +++ b/src/Apm/Span.php @@ -0,0 +1,52 @@ +timer = $timer; + $this->collection = $collection; + + $this->start = $timer->getElapsedInMilliseconds(); + } + + public function setName(string $name) + { + $this->name = $name; + } + + public function setType(string $type) + { + $this->type = $type; + } + + public function end() + { + $duration = round($this->timer->getElapsedInMilliseconds() - $this->start, 3); + $this->collection->push([ + 'name' => $this->name, + 'type' => $this->type, + 'start' => $this->start, + 'duration' => $duration, + ]); + } +} \ No newline at end of file diff --git a/src/Apm/SpanCollection.php b/src/Apm/SpanCollection.php new file mode 100644 index 0000000..19bd298 --- /dev/null +++ b/src/Apm/SpanCollection.php @@ -0,0 +1,15 @@ +collection = $collection; + $this->timer = $timer; + } + + public function startNewSpan(string $name = null, string $type = null): Span + { + $span = new Span($this->timer, $this->collection); + + if (null !== $name) { + $span->setName($name); + } + + if (null !== $type) { + $span->setType($type); + } + + return $span; + } +} \ No newline at end of file diff --git a/src/Providers/ElasticApmServiceProvider.php b/src/Providers/ElasticApmServiceProvider.php index efc3cf5..561c7f5 100644 --- a/src/Providers/ElasticApmServiceProvider.php +++ b/src/Providers/ElasticApmServiceProvider.php @@ -6,6 +6,8 @@ use Illuminate\Support\Collection; use Illuminate\Support\ServiceProvider; use PhilKra\Agent; +use PhilKra\ElasticApmLaravel\Apm\SpanCollection; +use PhilKra\ElasticApmLaravel\Apm\Transaction; use PhilKra\ElasticApmLaravel\Contracts\VersionResolver; use PhilKra\Helper\Timer; @@ -13,8 +15,6 @@ class ElasticApmServiceProvider extends ServiceProvider { /** @var float */ private $startTime; - /** @var Timer */ - private $timer; /** @var string */ private $sourceConfigPath = __DIR__ . '/../../config/elastic-apm.php'; @@ -68,12 +68,17 @@ public function register() }); $this->startTime = $this->app['request']->server('REQUEST_TIME_FLOAT') ?? microtime(true); - $this->timer = new Timer($this->startTime); + $timer = new Timer($this->startTime); - $this->app->instance(Timer::class, $this->timer); + $collection = new SpanCollection(); + + $this->app->instance(Transaction::class, new Transaction($collection, $timer)); + + $this->app->instance(Timer::class, $timer); $this->app->alias(Agent::class, 'elastic-apm'); - $this->app->instance('query-log', collect([])); + $this->app->instance('query-log', $collection); + } /**